您的位置:首页 > 其它

自己动手写病毒修复程序

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: