自己动手写病毒修复程序
2010-09-02 17:57
337 查看
哎,在这里先鄙视360一下,昨天我真的很生气!发样本给他等了两天,他回复说360可以查杀了,安装上几百兆的360杀毒后一杀,我的那个心痛啊!竟然是直接删除感染文件!实在无语,我都知道自己全盘EXE被感染了,还要你来删除?!,要删除我一个批处理早删了,一个特征码的提取也需要两天的时间?!
心凉啊~国货当自强,就是这样自强的?呼~不说了,自己动手写个修复工具好得很,花了半天的时间去网上下载VS2008,OD等工具,然后又花了半天的时间分析加编程,终于写出来,下面说下思路...
由于我的系统里面已经没有活动的病毒了,只是一些带毒文件需要修复,所以也没必要去分析病毒行为了,只需对比一下感染文件和原文件的差异,修复即可...
【1.分析】
用文件比较工具对比两个文件:
搜索差异
1. Z:/Documents and Settings/feng/桌面/病毒样本/病毒样本/VStart.exe: 920,064 bytes
2. Z:/Documents and Settings/feng/桌面/病毒样本/病毒样本/VStart_Infected.exe: 1,164,800 bytes
Offsets: 16 进制
CE: 03 04 ; 区块数 增加了1
E5: E0 9C ; SizeOfCode -RawSize
E6: 0D 11
F0: E0 00 ; 入口地址被 修改
F1: 4F A0
119: A0 60 ; SizeOfImage -VirtualSize
11A: 27 2B
238: 00 DD ;最后一个区块全部清0
239: 00 79
23A: 00 A4
23C: 00 E0
23D: 00 4F
23E: 00 27
241: 00 C0
242: 00 03
245: 00 A0
246: 00 27
249: 00 BC
24A: 00 03
24D: 00 0A
24E: 00 0E
25A: 00 34
25B: 00 08
25C: 00 20
25F: 00 E0
25 差异 找到。
配合Stud_PE不难得到上述信息即
1.感染文件增加了一个区段
2.感染文件的入口地址被修改指向新增区段
3.代码块大小和映像大小改变
【2.修复】
1)首先肯定是提取特征码,用OD载入被感染文件
0067A000 > $ 55 push ebp
0067A001 . 8BEC mov ebp, esp
0067A003 . 81EC 84000000 sub esp, 84
0067A009 . 64:FF35 30000>push dword ptr fs:[30]
0067A010 . 58 pop eax
0067A011 . 8945 DC mov dword ptr [ebp-24], eax
0067A014 . C745 EC 00B80>mov dword ptr [ebp-14], 3B800
0067A01B . C745 CC 433A5>mov dword ptr [ebp-34], 325C3A43
0067A022 . C745 D0 63613>mov dword ptr [ebp-30], 37346163
0067A029 . C745 D4 39646>mov dword ptr [ebp-2C], 2E646439
0067A030 . C745 D8 65786>mov dword ptr [ebp-28], 00657865
从第三行开始取12个字节作为特征码(感觉这部分代码还是比较独特的)再配合多出来的区段作为第二特征...
入口地址为最后一个区段的起始地址,这是一个很独特的特征
判断特征码的代码如下:
unsigned long RVAEntry = PEhead->OptionalHeader.AddressOfEntryPoint; bool befuckentry = false; bool befucksection = false; IMAGE_SECTION_HEADER* ISH = (IMAGE_SECTION_HEADER*)((unsigned long)PEhead + sizeof(IMAGE_NT_HEADERS)); ISH+=(PEhead->FileHeader.NumberOfSections - 1); if(ISH->VirtualAddress == RVAEntry) { befucksection = true; DP1(_T("%ws有感染的节区!"),ps); } unsigned long RAEntry = GetRAbyRVA(hMapView,RVAEntry); if(*(unsigned long *)(RAEntry+0x04)== 0x0084EC && *(unsigned long *)(RAEntry+0x08)== 0x35FF6400 && *(unsigned long *)(RAEntry+0x0C)== 0x0030) { befuckentry = true; DP1(_T("%ws有感染的特征"),ps); }
2).修复OEP
在感染文件的入口向下偏移0x26A处 有一个JMP,是跳转到真正的OEP的
$+260 > . 40 inc eax
$+261 > . 8945 80 mov dword ptr [ebp-80], eax
$+264 > .^ EB 95 jmp short 0067A1FB
$+266 > > C9 leave
$+267 > . 83C4 04 add esp, 4
$+26A > .- E9 71ADFFFF jmp 00674FE0
$+26F > 4D db 4D ; CHAR 'M'
$+270 > 5A db 5A ; CHAR 'Z'
$+271 > 90 nop
因此 RealOEP=FakeOEP+[OEP+0x26F]
3).修复其他部分
代码块大小和映像大小的修复都很简单,最后记得把新增区段的区段表清0...
主要修复函数 DealPE代码
BOOL DealPE(const TCHAR* ps) { HANDLE hMapView = 0; bool rets = false; try { HANDLE hFile = CreateFile(ps,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if(hFile == INVALID_HANDLE_VALUE) return false; HANDLE hFileMapping = CreateFileMapping(hFile,0,PAGE_READWRITE,0,0,0); CloseHandle(hFile); hMapView = MapViewOfFile(hFileMapping,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0); CloseHandle(hFileMapping); if(!hMapView) { return FALSE; DP1(_T("MapViewOfFile失败!-->%ws"),ps); } IMAGE_DOS_HEADER* doshead = (IMAGE_DOS_HEADER*)hMapView; if(doshead->e_magic != 'ZM') { return FALSE; DP1(_T("检测MZ标志失败!-->%ws"),ps); } IMAGE_NT_HEADERS* PEhead = (IMAGE_NT_HEADERS*)((unsigned long)doshead + (unsigned long)doshead->e_lfanew); if(PEhead->Signature != 'EP') { return FALSE; DP1(_T("检测PE标志失败!-->%ws"),ps); } NUM_process++; tmp.Empty(); tmp.Format(L"%d",NUM_process); ::SendMessage(HNUM1,WM_SETTEXT,0,(LPARAM)tmp.GetBuffer()); ::SendMessage(HMSG,WM_SETTEXT,0,(LPARAM)ps); unsigned long RVAEntry = PEhead->OptionalHeader.AddressOfEntryPoint; bool befuckentry = false; bool befucksection = false; IMAGE_SECTION_HEADER* ISH = (IMAGE_SECTION_HEADER*)((unsigned long)PEhead + sizeof(IMAGE_NT_HEADERS)); ISH+=(PEhead->FileHeader.NumberOfSections - 1); if(ISH->VirtualAddress == RVAEntry) { befucksection = true; DP1(_T("%ws有感染的节区!"),ps); } unsigned long RAEntry = GetRAbyRVA(hMapView,RVAEntry); if(*(unsigned long *)(RAEntry+0x04)== 0x0084EC && *(unsigned long *)(RAEntry+0x08)== 0x35FF6400 && *(unsigned long *)(RAEntry+0x0C)== 0x0030) { befuckentry = true; DP1(_T("%ws有感染的特征"),ps); } if(befucksection&&befuckentry) { NUM_infect++; tmp.Empty(); tmp.Format(L"%d",NUM_infect); ::SendMessage(HNUM2,WM_SETTEXT,0,(LPARAM)tmp.GetBuffer()); DP1(_T("正在修复%ws"),ps); DWORD JMP=*(DWORD *)(RAEntry+0x26B); DWORD realEntry =RVAEntry+0x26F+JMP; PEhead->OptionalHeader.AddressOfEntryPoint = realEntry; //修复入口 size_t realfilelen = ISH->PointerToRawData; PEhead->OptionalHeader.SizeOfCode -= ISH->SizeOfRawData; //修复代码块大小 --(PEhead->FileHeader.NumberOfSections); //修复区段个数 PEhead->OptionalHeader.SizeOfImage -= ISH->Misc.VirtualSize; //修复映像大小 memset((void *)ISH,0,0x28); //清除区块表 UnmapViewOfFile(hMapView); hMapView = 0; HANDLE hFile = CreateFile(ps,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if(hFile == INVALID_HANDLE_VALUE) return false; SetFilePointer(hFile,realfilelen,0,FILE_BEGIN); SetEndOfFile(hFile); CloseHandle(hFile); DPS(_T("========修复成功!========")); NUM_repair++; tmp.Empty(); tmp.Format(L"%d",NUM_repair); ::SendMessage(HNUM3,WM_SETTEXT,0,(LPARAM)tmp.GetBuffer()); rets = true; } } catch(...) { } if(hMapView)UnmapViewOfFile(hMapView); return rets; }
==================================================================================
= =!! 好像分析得一点都不具体,不过有基础的同学应该能看懂的...
上源代码:
http://www.breeze356.com/rar/VKiller_src.rar
相关文章推荐
- 自己动手写病毒修复程序
- 自己动手编写操作系统_引导程序
- 自己动手写的内存管理程序Ver0.1
- 自己动手敲的小程序
- 自己动手搭建 Redis 环境,并建立一个 .NET HelloWorld 程序测试(转)
- 自己动手写操作系统 将引导程序成功写入优盘启动电脑
- WPF 自己动手来做安装卸载程序
- 自己动手写一个简单的Windows shell扩展程序
- (转)修复 artDialog 双击遮罩层就会自动关闭的bug.... 自己动手....
- 自己动手修复HP的的烂鼠标
- 自己动手写内核(第9课:系统调用和可执行程序)(原创)
- 自己动手制作Debian程序图标
- 自己动手写一个简单的Windows shell扩展程序
- 自己动手搭建 MongoDB 环境,并建立一个 .NET HelloWorld 程序测试
- ROS学习笔记(一):自己动手写一个ROS程序
- mfc学习笔记之如何自己动手实现最简单的mfc程序
- 自己动手编译、运行Java程序
- 修复 artDialog 双击遮罩层就会自动关闭的bug.... 自己动手....
- 如何自己动手jlink v8固件修复
- Java高并发程序-Chapter3 JDK并发包(第十四讲)同步控制之自己动手实现 CoutDownLatch