PE感染型病毒专杀的编写
PE感染型病毒专杀的编写
平常我们虚拟机经常下一些乱七八糟的软件,免不了中招,关键是虚拟机中招不要紧,主机中招就比较郁闷了,这不朋友的电脑在和虚拟机进行交互软件的时候中招了,我帮她分析了下,这个病毒只是感染全盘的 .exe的程序,通过添加新节,写入病毒代码至新节,然后跳转至入口点,病毒的具体功能就懒得分析了,我们直奔今天的主题 “病毒专杀的编写”。
首先我们拿0llydbg载入一个感染过的程序,如下图,我们可以看到入口点已经被改到新节表中了,以下就是病毒的入口点。
通过查看上面的代码,我们发现下面有一个异或的解密过程,那么我们直接断点在$0054701D。
断下来后,F9执行,OK病毒体已经解密完成,我们继续跟入CALL 005471A0偏移中,
我们发现执行CALL 005471A0, 会将其00547023压入堆栈,然后我们进入到这个过程005471A0,我们发现mov eax, ebp add eax, 4 将eax指向栈顶,因为栈顶存储005471A0, 然后我们继续向下分析mov edi, [eax] ,此时取出005471A0至edi寄存器,我们继续向下看Sub edi, 5 mov eax, dword [edi+c] add eax, [edi+8] 执行以上3句指令时eax就是原来程序的入口点。
通过以上分析我们大概了解了入口点是存储在CALL 005471A0 指令其后的内存偏移处,并且是加密的。那么我们写专杀关键是找出原来程序的入口点,然后清除病毒体。但是由于这个病毒的入口点是加密存储的,所以我们必须进行解密操作。又由于这个病毒的入口点不是固定的,并且解密头也不是固定的,那么我们的专杀必须要做到以下几点。
1、找出固定特征
2、根据固定特征获取到病毒体偏移 病毒体的解密HASH 、病毒体的大小。
3、然后进行对病毒体解密,然后找出我们需要的入口点。
我分析了几个感染后程序的病毒入口点,这个病毒的入口点做了随机化处理,但是有几个特征是固定的,那就是它需要将病毒体偏移、解密HASH、病毒体大小传入寄存器,通常传入寄存器无非两种,一个是push xxxx ,pop 寄存器,然后一种是直接mov 寄存器、xxxx。这样它的指令长度都是5字节,但是由于它每个感染程序传入的寄存器都不太一样,所以我们必须将范围设置大点。
我们可以通过以下思路,通过长度反汇编引擎搜索指令长度,如果指令长度是5,那么就判断是不是push 或者是(mov eax — mov edi) 然后获取其后的值,由于它的顺序是固定的就是先传入HASH、解密偏移、解密大小。所以我们做个循环然后通过长度反汇编引擎搜索指令,直到找到这3个数据,然后退出循环,进行解密。
我们解密完的内存病毒体如上图,我们看到e8 7D 01 00 00 就是我们的call 解密体的过程,通过刚刚上面的分析,me8 7D 01 00 00 后面的相对偏移$0c 和$08 处分别是源程序的基地址和相对偏移。
到了这里,我们基本上对整个专杀的过程十分熟悉了吧,那么还等什么呢,直接上专杀代码吧。
function ClearVirusFile(VirusFile, NewFile: string): Boolean;
var
Pe: TPeFile;
EntryAddr: DWORD;
SectionNum: DWORD;
VirusBytes: PChar;
I: DWORD;
HashKey: DWORD;
Data: DWORD; // 解密数据偏移
DataLen: DWORD;
NewEntryAddr: DWORD;
Len: ULONG;
begin
Result:= False;
Pe:= TPeFile.Create;
Pe.LoadFromFile(PChar(VirusFile));
try
if Pe.ValidHeaders then
begin
HashKey:= 0;
Data:= 0;
EntryAddr:= Pe.ImageNtHeaders.OptionalHeader.AddressOfEntryPoint;
SectionNum:= Pe.ImageNtHeaders.FileHeader.NumberOfSections;
// 如果入口点设置为最后一个节
if (EntryAddr >= Pe.ImageSections[SectionNum-1].VirtualAddress) then
begin
VirusBytes:= PChar(DWORD(Pe.lpBuffer) +
Pe.ImageSections[SectionNum-1].PointerToRawData);
i:= 0;
while i < Pe.ImageSections[SectionNum-1].SizeOfRawData do
begin
GetInstLenght(@VirusBytes[i], @Len);
if Len = 5 then
begin
if HashKey = 0 then
begin
if (Byte(VirusBytes[i]) = $68) or ((Byte(VirusBytes[i]) >= $B8)
and (Byte(VirusBytes[i]) <= $BF)) then
HashKey:= PDWORD(@VirusBytes[i+1])^;
end else
begin
if (Data = 0) then
begin
if (Byte(VirusBytes[i]) = $68) or ((Byte(VirusBytes[i]) >= $B8)
and (Byte(VirusBytes[i]) <= $BF)) then
begin
Data:= PDWORD(@VirusBytes[i+1])^;
end;
end else
begin
if (Byte(VirusBytes[i]) = $68) or ((Byte(VirusBytes[i]) >= $B8)
and (Byte(VirusBytes[i]) <= $BF)) then
begin
DataLen:= PDWORD(@VirusBytes[i+1])^;
Break;
end;
end;
end;
end;
i:= i + Len;
end;
if HashKey <> 0 then
begin
// 查找入口点
if Data <> 0 then
begin
Data:= Pe.RVaToFileOffset(Data - Pe.ImageNtHeaders.OptionalHeader.ImageBase );
Data:= Data + DWORD(Pe.lpBuffer);
i:= DataLen;
while i > 0 do
begin
PDWORD(Data+i)^ := PDWORD(Data+i)^ xor HashKey;
Dec(i, 4);
end;
// 设置入口点和基地址
Pe.SetAddressOfEntryPoint(PDWORD(Data+$c+4)^);
Pe.SetImageBase(PDWORD(Data+$8+4)^);
// 删除病毒体
Pe.DeleteBytes(Pe.GetHighestSectionSize,
Pe.FileSize - Pe.GetHighestSectionSize);
//Pe.DeleteSection(SectionNum-1);
Pe.SaveToFile(NewFile);
Result:= True;
end;
end;
end;
end;
finally
Pe.Free;
end;
end;
评论17次
你在看雪混过吧
给力 ,学xi了
图片挂了,楼主换图床吧
学xi了多谢楼主
这种病毒是最痛苦的,一旦感染了满盘的程序啊...各种痛苦
很不错的文章,学xi了
在360总部发这个,是想被招了吗。。
楼主碉堡了..顶个
给力啊!
貌似很叼,不过太菜了看不懂~~~
回帖总是错误啊
不发吾爱去。。。。
不明觉厉
楼主肯定会免杀
眼都看花了,还是没看懂
强势插入,看的老夫眼花了。