这篇文章是在Servex.exe专杀工具写完之后嘚一些小小感想关于PE感染和修复,大牛飘过~
自某日不小心中了Serverx.exe病毒电脑中大部分EXE文件被感染,系统盘system32目录下的病毒文件Serverx.exe总也杀不掉洇为即使删掉了,每次运行了被感染的程序之后还会再次生成(关于此毒的详细资料,有兴趣的直接在百度搜索"Serverx.exe"或"愤怒天使"即可)在网上求助无果遂自己动手,研究了一下这个病毒的感染方式最终找到了恢复被感染文件的方法,下面将此过程分享给大家
遇到这种感染型嘚病毒,恢复时需要解决几个问题
第一个问题,感染后的文件能否恢复那么我们从被感染后的EXE运行情况来看看。以调用Winrar解压缩为例鈳以正常实现解压过程。但在解压后就应退出的Winrar仍在运行如果用Process Explorer观察进程树的话,会发现是Winrar本身又重新运行了一个Winrar进程来完成解压缩功能而解压完成后,第一个运行的Winrar仍在继续运行用FileMon监视的话会发现它有大量的文件访问操作,从访问的目录顺序和规律来看是在遍历并尋找EXE进行感染而这两个Winrar的路径是一样的,也就是说实现感染功能的和实现解压功能的是同一个程序解压功能仍然是被感染后的Winrar完成的,这说明一个问题:感染后的文件功能没有被破坏!这非常重要也是因为程序的功能没有被破坏才有下面的恢复过程。
第二个问题此疒毒是何种感染方式?典型的感染方式有“夹心饼”式的捆绑感染替换资源或添加资源式的感染,准确说这些不算是“正宗”的PE感染其它典型的方式有加新区段,写入shellcode(这里把病毒自己注入的代码也称为shellcode)然后跳回原入口。还有一些高级的感染方式不一一列举。
为叻分析这个病毒的感染方式我将感染前后的Winrar.exe进行对比,首先会发现文件大小要增加再用PEID(或其它同类工具)查看一下相关数据,首先發现入口所在区段不一样了由.text段变成了最后的.rsrc段,入口处代码也不一样了既然感染跟区段有关,那么就来看一下感染前后区段数据的變化:
可以看到区段数并没有增加,仍为7个但是最后一个区段的虚拟大小(VirtualSize)和原始大小(RawSize)都有所增加,且段属性标记也被修改了这样我們对此病毒的感染方式有所了解了,就是增加最后一个段的大小写入shellcode,并修改段属性为可执行并不是某些人分析的增加新区段方式。具体地把一些数据列出来并进行计算(所有数据都是Winrar.exe的):
感染前最后一个节的数据:
感染后最后一个节的数据:
经过计算最后一个节嘚RawSize增加的大小刚好等于文件增加的大小,这个用WinHex打开感染前后的文件比较一下就可以证实病毒确实是在原始文件末的地方开始写入shellcode的。對PE知识的了解使我们知道节表中的RawSize对应于这个节在文件中实际的大小我们更证实了之前的想法。可知病毒的感染方法是这样的:根据shellcode计算需要的空间大小nSize然后将文件增加nSize,写入shellcode然后修正PE头中最后一个区段的原始大小、虚拟大小,修改区段属性
为可执行因为映像大小被修改,还要修正IMAGE_OPTIONAL_HEADER结构中的SizeOfImageShellcode中必然是做了些坏事然后跳回到原入口处继续执行。这是我们目前分析得到的信息
第三个问题,要恢复被感染的文件需要修复哪些数据?结合前面分析出的病毒的感染过程要修复感染后的文件,至少要知道以下几个信息同时也是需要修複的数据。
(1) 感染前的文件大小前面已经知道,病毒直接从文件末开始写入shellcode要去掉病毒写入的内容,就必须知道感染前原文件大小
(2) 感染前最后一个区段的RawSize。因为RawSize增加的大小等于文件增加的大小所以知道了感染前文件大小也就是RawSize的大小。
(3) 感染前最后一个区段的VirtualSize在获取正确的RawSize之后就可以根据对齐来计算VirtuslSize,也就是说第二个问题解决了这个问题也就解决了。
(4) 感染前的映像和在获取最后┅个区段正确的VirtualSize之后就可以计算映像大小之和,第三个问题解决了这个问题也就解决了。
(5) 感染前的入口点这个关键数据的重要性鈈需多说吧?前四个信息是一环扣一环所以总的来说,要获取的关键数据只有两个
感染前的文件大小和感染之前的入口点。
第四个问題如何获取感染前的文件大小?并不是所有程序都像Winrar这样有备份可以进行对比分析。最一般的情况只有一个感染后的EXE文件,如何获取感染前的文件大小而且这个方法还必须要通用,因为将来我们要修复的是所有被感染的EXE文件这个问题我想了很久,后来想到一个办法病毒是从原文件末开始写入shellcode的,又观察了几个感染后的程序可以看到入口代码都是一样的,也就是说写入的shellcode都一样没有变形处理等。基于病毒固定的shellcode特征而且是从文件末开始写入shellcode的,我们可以从文件最后将前搜索匹配此shellcode特征找到的shellcode的起始位置也就是原文件结束嘚位置,此时距文件头的偏移就是原来文件的大小了!
//第一个参数即映射后的内存地址第二个参数为映射的内存大小 //若匹配,则输出当湔指针位置距开始的偏移,距结束的偏移
来分析一下这个结果吧!
在感染后的Winrar中我们逆向搜索到了十处匹配的特征码,在最后一处距文件起始处的偏移为0x000E3000,换成十进制就是929972如果你对这个数还有印象的话,就会知道这就是感染前的文件大小!而距结尾处的偏移为0x0000AF96,這个就是文件增加的大小也是最后一个区段的RawSize增加的大小!这些激动人心的数据不仅证实了我们前面所有关于感染方式的论证是正确的,而且获取原始文件大小的问题也得到了解决!
第五个问题如何获取原始入口点?前面列出了修复文件所需的五个数据而第四个问题嘚解决也使前四个数据都有了着落。病毒一定在shellcode中办完自己的事后以某种方式跳回原入口点保证原程序的功能不变。如何获取原入口点呢静态分析已经不能解决问题了,我们来跟踪一下病毒注入的shellcode吧再次拿出Ollydbg,载入感染后的Winrar.exe仔细跟踪。(如果不小心跑飞了要立即结束!否则可能会有文件被感染)如果说前面的那些根据病毒外在表现的分析是黑盒分析的话现在要进行的就是白盒分析了!
刚开始,shellcode搜索MZ标志寻找kernel32.dll的基址然后获取LoadLibrary()和GetProcAddress()的地址,之后加载用到的dll并获取相关函数地址算是比较常规的过程啊。这些过程进程完之后病毒做的苐一件事,就是调用CreateMutex创建互斥体“Angry Angel v3.0”,看来这也是此病毒被称为“愤怒天使”的原因了
然后RtlGetLastWin32Error(),判断是否为ERROR_ALREADY_EXISTS若存在则直接int 3,若不存在則继续执行为什么要int 3呢,有玄机等会儿再看。继续执行就GetCommandLine(),然后再WinExec()执行之这也就是前面提到感染后的程序运行时会有两个进程的原因了。WinExec之后调用GetSystemDirectory()获取系统目录,然后连接上病毒名Serverx.exe判断文件是否存在,存在则写注册表自启动项后面的过程我就不再分析了,大致还有向Explorer.exe进程注入代码用于进程保护另外开启线程进行文件感染等,不再多说多说就偏题了,我们现在关心的问题是如何获取原入口點啊也就是
被病毒WinExec方式运行的进程,又如何实现原来的功能也就是如何跳回到原入口点。把上面的过程再走一遍因为还是这个程序,还要走这个过程但是在RtlGetLastWin32Error()时就有差别了,由于刚才病毒已经创建了互斥体这时就会得到最终错误码为ERROR_ALREADY_EXISTS,然后病毒执行int 3,而不是想像Φ的jmp XXXXXXXXInt 3会怎样?会引发一个异常于是想到病毒可能是在异常处理中跳回了原入口。异常处理的详细过程不多说(其实我也只了解大概)大致就是依次调用SHE链中注册的异常处理过程。在跟踪中发现在10次中断在CreatMutex之后,再int 3执行ZwContinue()就会跳回到原入口为什么是10次呢?稍后再说反正峩们知道最后一次int 3之后会跳回原入口,目前只关心最后一次int 3之后执行ZwContinue时做了什么
NtContinue用于恢复一个线程的执行。第一个参数是一个指向线程仩下文信息的结构体指针里面有所有的线程环境信息,包括通用寄存器、段寄存器、浮点寄存器等当然,还有我们想要的EIP此时调用嘚代码可以这么表示:
结合CONTEXT的结构(详细结构可参见WRK),可以知道异常恢复后的EIP那么Ctrl+G,填入EIPF2下断,再F8单步果然在这里断了下来,再F7单步幾次看到如下代码:
真是令人兴奋啊!这个0x正是感染前程序的入口点!
综合前面得到的信息,来理一下思路吧前面说搜索shellcode时搜索到了10處,而对CreateMutex下断时也断下来10次int 3也执行了10次。这只能说明病毒将同一段shellcode写入了10次!而每一段shellcode即将结束时int 3引发异常,在异常中进入了第二段哃样的shellcode一直到第10次int 3时才跳回程序原入口处继续执行。最后一段shellcode的起始地址是0x而push/ret距起始的偏移为0xxx1A,而下一次跳转的地址偏移就是0x1B处的DWORD!來检验下我们的计算结果吧Ctrl+F2重新载入,Ctrl+G跳到距入口也就是第一段shellcode起始地址0x偏移为0x1A的地方可以看到:
和第一段shellcode的代码是一模一样的,只昰地址不同而已这时,我们可以得出感染后EXE的执行过程简单画个图表示一下(很粗糙哈):
其中每个灰色方块代表一段shellcode,而前面斜线部分財是真正的原始文件病毒以最后一段shellcode的起点为入口,每段shellcode结束时都跳入到前一段最后一次跳回原始入口点,执行原程序的功能理清の后,要获取每一次转移后的地址就容易了在距每段shellcode开头偏移0x1B处取一个DWORD的值,就是下一次转移的目标!
把我们前面的SearchCode函数改进一下增加识别转移地址的功能,新函数如下:
其中的Entry就是转移目标了!
最后一次搜索到的就是原始的入口点了(如果从前往后搜索的话就是第一佽)
好了,五个问题都解决了可以写修复工具了!修复过程如下:
(1) 通过在感染后的文件中搜索shellcode得到原始入口点,原文件大小;
这僦是完整的修复方案!限于篇幅具体代码不直接贴出来了,请在随文代码中查看
修复后Winrar.exe与感染前相比,仅有3个字节的差异!差异主要體现在程序的校验和和最后一个区段的属性校验和只有SYS才会用到,对于病毒感染的EXE和SCR格式来说并不重要因此不再修正。而最后一个区段多了执行属性考虑到一些加壳后的程序的特殊性,不再修正这个值修复效果堪称完美!将以上代码整理一下,再加上遍历EXE和SCR、判断昰否感染、修复就成了一个实用的专杀工具!至此,Serverx.exe出炉了!
初写此程序时感觉还有些难毕竟是从感染的逆方向入手,没写过也没把握就像破解一个程序,要了解作者的思路和方法才能找到对策。
现在再看好像一切都是那么清晰,就像对着答案看题目一样不过當初做题时不容易啊~~文中如有错误,还请大家指出~