标 题: MoleBox 脱壳的一些总结
作 者: CCDebuger
时 间: 2007-04-14,09:41
链 接: http://bbs.pediy.com/showthread.php?t=42700
【文章标题】: MoleBox 脱壳的一些总结
【文章作者】: CCDebuger
【软件名称】: Ultra Video Converter
【下载地址】: http://www.zxmedia.com/ultra_videoconverter.exe
【作者声明】: 无他,仅是自己调试时的一些记录,方便查阅而已
--------------------------------------------------------------------------------
【详细过程】
论坛上写MoleBox脱壳教程的已经有不少了,大家应该知道MoleBox会加密输入表。我看了几个MoleBox加的壳和MoleBox的主程序,发现这个壳还是挺有意思的。只要你找好关键点,可以 dump 出来一个完整的未加壳前的程序,MoleBox的那个加密输入表的功能根本没用。这篇文章只是我自己的一个调试记录,只是为了方便自己查阅。大家可以参考一下。OK,现在进入正题。
一、主程序脱壳
在 OD 中忽略所有异常,载入程序:
00470B53 > E8 00000000 CALL Ultra_Vi.00470B58 ; OD载入后停在这
00470B58 60 PUSHAD
00470B59 E8 4F000000 CALL Ultra_Vi.00470BAD ; F8到这里的时候在命令行中输入hr esp
完成上面的操作后,直接按 F9,会断在这里:
00470731 58 POP EAX ; 断在这里
00470732 58 POP EAX
00470733 FFD0 CALL EAX ; 这里F7进去就是OEP
我们到 00470733 地址处时按 F7 进去,就到 OEP 了:
0042304E 55 PUSH EBP ; OEP
0042304F 8BEC MOV EBP,ESP
00423051 6A FF PUSH -1
00423053 68 90A74200 PUSH Ultra_Vi.0042A790
00423058 68 B8314200 PUSH Ultra_Vi.004231B8 ; JMP 到 msvcrt._except_handler3
0042305D 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
00423063 50 PUSH EAX
00423064 64:8925 0000000>MOV DWORD PTR FS:[0],ESP
0042306B 83EC 68 SUB ESP,68
0042306E 53 PUSH EBX
0042306F 56 PUSH ESI
00423070 57 PUSH EDI
00423071 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
00423074 33DB XOR EBX,EBX
00423076 895D FC MOV DWORD PTR SS:[EBP-4],EBX
00423079 6A 02 PUSH 2
0042307B FF15 38764200 CALL DWORD PTR DS:[427638] ; msvcrt.__set_app_type
看 OEP 开始的代码就知道这是个典型的 VC 程序。
记住 OEP 的 RVA = 0042304E - 00400000 = 2304E。随便找个 API 调用,如 0042307B 处的这句。左键选择这句,按鼠标右键,选择弹出菜单 数据窗口中跟随->内存地址。现在在数据窗口中按CTR+G转到427638(这样做主要是为了便于OD记住这个地址),重新启动程序,在数据窗口中转到我们上次记住的地址,设内存写入断点。在数据窗口中按右键切换一下视图,选择长型->地址,这样便于观察。经过几次中断后,数据窗口中会看到这样的内容:
00427624 73DC067B MFC42.#952_??_afxSOCK@@3UAFX_SOCK_CALL@@A@@YAXXZ
00427628 73DCC3C8 MFC42.#3716_?GetRuntimeClass@CSliderCtrl@@UBEPAUCRuntimeClass@@XZ
0042762C 73D8ACCE MFC42.#541_??0CStringArray@@QAE@XZ
00427630 00000000
00427634 77C1EE2F msvcrt._controlfp
00427638 0002E8E4
0042763C 0002E8D6
00427640 0002E8C6
00427644 0002E8B6
00427648 0002E8A2
0042764C 0002E896
00427650 0002F52C
00427654 0002E87C
00427658 0002E874
0042765C 0002E866
可见00427638下面的都没被填充,而上面已经填入了API函数的实际地址了。重来,在上面填充过地址的地方重设内存断点,直到输入表部分都显示为这样的:
00427638 0002E8E4
0042763C 0002E8D6
00427640 0002E8C6
00427644 0002E8B6
00427648 0002E8A2
现在就可以dump了。用16进制工具打开dump后的文件,推荐用 010Editor。先定位到输入表所在区段,查找 ASCII 字串".dll",看看找到的地方,比如看到了 KERNEL32.dll。记下 KERNEL32.dll 的开始地址,逆序转换一下(可以用 Hpmbcalc Hex Calculator 来转换),再在输入表所在段中搜索 KERNEL32.dll 开始地址的逆序字串,一般只会找到一个地方。根据 IAT 的结构,名称在第四个字段,往前再数12个字节就是这个 DLL 调用信息开始的地方。再根据 IAT 最后以20个0结束,就可以确定输入表的开始地址和大小了。把我们找到的 OEP 和 IAT 信息用 PE 编辑工具填入 dump 后的文件就可以了。
上面说的是一种跟踪加壳程序处理输入表比较通用的方法。对于 MoleBox,为了得到完好的输入表,可以 BP VirtualProtect 设断点。这也分两种情况:
1、MoleBoxPro_2.6.1.2387主程序脱壳例子
先到MoleBox壳的EP,设断 BP VirtualProtect,中断两次后返回,来到下面的地方:
0043AB9D FF15 AC774400 CALL DWORD PTR DS:[4477AC] ; kernel32.VirtualProtect
0043ABA3 8B15 84764400 MOV EDX,DWORD PTR DS:[447684] ; [00447684]=00CD1F00,地址00CD1F00中就是OEP
0043ABA9 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18]
0043ABAC 0342 08 ADD EAX,DWORD PTR DS:[EDX+8] ; [00CD1F08]=00027B00,输入表的RVA。这里直接dump文件
0043ABAF 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX
0043ABB2 C705 14794400 0>MOV DWORD PTR DS:[447914],0
0043ABBC 6A 00 PUSH 0
0043ABBE 68 246C4400 PUSH mbox2w.00446C24 ; ASCII "EXECUTABLE"
0043ABC3 8B0D 10794400 MOV ECX,DWORD PTR DS:[447910] ; mbox2w.00400108
0043ABC9 51 PUSH ECX
0043ABCA 8B55 E8 MOV EDX,DWORD PTR SS:[EBP-18]
0043ABCD 52 PUSH EDX
0043ABCE 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
0043ABD1 50 PUSH EAX
0043ABD2 E8 E9FAFFFF CALL mbox2w.0043A6C0
0043ABD7 83C4 14 ADD ESP,14
0043ABDA E8 B30F0000 CALL mbox2w.0043BB92
0043ABDF 25 FF000000 AND EAX,0FF
0043ABE4 85C0 TEST EAX,EAX
0043ABE6 74 15 JE SHORT mbox2w.0043ABFD
0043ABE8 E8 B60F0000 CALL mbox2w.0043BBA3
0043ABED 25 FF000000 AND EAX,0FF
0043ABF2 85C0 TEST EAX,EAX
0043ABF4 74 02 JE SHORT mbox2w.0043ABF8
0043ABF6 ^ EB F0 JMP SHORT mbox2w.0043ABE8
0043ABF8 E8 950F0000 CALL mbox2w.0043BB92
0043ABFD 68 846C4400 PUSH mbox2w.00446C84 ; ASCII "imm32.dll"
0043AC02 FF15 18774400 CALL DWORD PTR DS:[447718] ; kernel32.GetModuleHandleA
0043AC08 8945 E4 MOV DWORD PTR SS:[EBP-1C],EAX
0043AC0B 837D E4 00 CMP DWORD PTR SS:[EBP-1C],0
0043AC0F 74 0E JE SHORT mbox2w.0043AC1F
0043AC11 68 846C4400 PUSH mbox2w.00446C84 ; ASCII "imm32.dll"
0043AC16 8B4D E4 MOV ECX,DWORD PTR SS:[EBP-1C]
0043AC19 51 PUSH ECX
0043AC1A E8 31000000 CALL mbox2w.0043AC50
0043AC1F 68 746C4400 PUSH mbox2w.00446C74 ; ASCII "oleoaut32.dll"
0043AC24 FF15 18774400 CALL DWORD PTR DS:[447718] ; kernel32.GetModuleHandleA
0043AC2A 8945 F0 MOV DWORD PTR SS:[EBP-10],EAX
0043AC2D 837D F0 00 CMP DWORD PTR SS:[EBP-10],0
0043AC31 74 0E JE SHORT mbox2w.0043AC41
0043AC33 68 646C4400 PUSH mbox2w.00446C64 ; ASCII "oleaout32.dll"
2、极品时刻表的例子
如果未发现与上面代码类似的内容,可以结合堆栈来看。比如极品时刻表,Delphi 程序,里面是aspack的壳。BP VirtualProtect第一次断下来的时候看堆栈:
0012FDB8 004F621C /CALL 到 VirtualProtect 来自 JPSKB061.004F6216
0012FDBC 004E9F5C |Address = JPSKB061.004E9F5C
0012FDC0 00000004 |Size = 4
0012FDC4 00000004 |NewProtect = PAGE_READWRITE
0012FDC8 0012FDCC \pOldProtect = 0012FDCC
0012FDCC 00000000
0012FDD0 003D20EC
0012FDD4 005021B8 JPSKB061.005021B8
0012FDD8 00000000
0012FDDC /0012FE30
0012FDE0 |004F5AA6 返回到 JPSKB061.004F5AA6 来自 JPSKB061.004F61D0
0012FDE4 |004E9F5C JPSKB061.004E9F5C
0012FDE8 |00501B44 ASCII "EXECUTABLE"
0012FDEC |004E9F6C ASCII "kernel32.dll"
0012FDF0 |00000001
0012FDF4 |00000000
0012FDF8 |00000000
0012FDFC |0045AB2C JPSKB061.0045AB2C
0012FE00 |00501B4E JPSKB061.00501B4E
0012FE04 |00501B4E JPSKB061.00501B4E
0012FE08 |C1CC0928
0012FE0C |39ADD078
0012FE10 |004E9F79 JPSKB061.004E9F79
0012FE14 |004E9F6C ASCII "kernel32.dll"
0012FE18 |004E9F5C JPSKB061.004E9F5C
0012FE1C |004E9F6C ASCII "kernel32.dll"
0012FE20 |7C800000 kernel32.7C800000
0012FE24 |FA46F001
0012FE28 |004E9F5C JPSKB061.004E9F5C
0012FE2C |00000000
0012FE30 ]0012FE74
0012FE34 |004F5C54 返回到 JPSKB061.004F5C54 来自 JPSKB061.004F58A0 ;右键选择这里,在反汇编窗口中跟随
0012FE38 |004E9FAC JPSKB061.004E9FAC
0012FE3C |00400000 ASCII "MZP"
0012FE40 |00400100 ASCII "PE"
0012FE44 |00501B44 ASCII "EXECUTABLE"
0012FE48 |00000000
0012FE4C |00000001
0012FE50 |00000000
0012FE54 |00000001
0012FE58 |00000000
0012FE5C |004EF564 ASCII ".adata"
0012FE60 |003D0000
0012FE64 |00400000 ASCII "MZP"
0012FE68 |0000000A
0012FE6C |004E9FAC JPSKB061.004E9FAC
0012FE70 |0000000A
0012FE74 ]0012FF94
0012FE78 |004EFF6B 返回到 JPSKB061.004EFF6B 来自 JPSKB061.004F5B10
0012FE7C |7C930738 ntdll.7C930738
在堆栈中的第二个返回上右键选择反汇编窗口中跟随,会来到这样的地方:
004F5C16 E8 65000000 CALL JPSKB061.004F5C80
004F5C1B ^ E9 4DFFFFFF JMP JPSKB061.004F5B6D
004F5C20 8B15 08255000 MOV EDX,DWORD PTR DS:[502508] ; 放OEP的地方
004F5C26 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
004F5C29 0342 08 ADD EAX,DWORD PTR DS:[EDX+8]
004F5C2C 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
004F5C2F C705 38275000 0>MOV DWORD PTR DS:[502738],0
004F5C39 6A 00 PUSH 0
004F5C3B 68 441B5000 PUSH JPSKB061.00501B44 ; EXECUTABLE
004F5C40 8B0D 34275000 MOV ECX,DWORD PTR DS:[502734] ; JPSKB061.00400100
004F5C46 51 PUSH ECX
004F5C47 8B55 F0 MOV EDX,DWORD PTR SS:[EBP-10]
004F5C4A 52 PUSH EDX
004F5C4B 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
004F5C4E 50 PUSH EAX
004F5C4F E8 4CFCFFFF CALL JPSKB061.004F58A0
004F5C54 83C4 14 ADD ESP,14 ; 返回到这里
004F5C57 68 841B5000 PUSH JPSKB061.00501B84 ; imm32.dll
004F5C5C FF15 9C255000 CALL DWORD PTR DS:[50259C] ; kernel32.GetModuleHandleA
004F5C62 8945 EC MOV DWORD PTR SS:[EBP-14],EAX
004F5C65 837D EC 00 CMP DWORD PTR SS:[EBP-14],0
004F5C69 74 0E JE SHORT JPSKB061.004F5C79
004F5C6B 68 841B5000 PUSH JPSKB061.00501B84 ; imm32.dll
004F5C70 8B4D EC MOV ECX,DWORD PTR SS:[EBP-14]
004F5C73 51 PUSH ECX
004F5C74 E8 F7010000 CALL JPSKB061.004F5E70
004F5C79 8BE5 MOV ESP,EBP
004F5C7B 5D POP EBP
004F5C7C C3 RETN
004F5C20就是我们要找的地方。
对上面的第二种情况,根据上面看到的代码,也可以尝试搜索命令序列:
MOV EAX,DWORD PTR SS:[EBP-10]
ADD EAX,DWORD PTR DS:[EDX+8]
MOV DWORD PTR SS:[EBP-8],EAX
如极品时刻表,搜索以上命令序列时,会找到这样的地方:
004F5C16 E8 65000000 CALL JPSKB061.004F5C80
004F5C1B ^ E9 4DFFFFFF JMP JPSKB061.004F5B6D
004F5C20 8B15 08255000 MOV EDX,DWORD PTR DS:[502508]
004F5C26 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10] ; 找到的地方
004F5C29 0342 08 ADD EAX,DWORD PTR DS:[EDX+8]
004F5C2C 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
004F5C2F C705 38275000 0>MOV DWORD PTR DS:[502738],0
004F5C39 6A 00 PUSH 0
004F5C3B 68 441B5000 PUSH JPSKB061.00501B44 ; EXECUTABLE
004F5C40 8B0D 34275000 MOV ECX,DWORD PTR DS:[502734] ; JPSKB061.00400100
004F5C46 51 PUSH ECX
004F5C47 8B55 F0 MOV EDX,DWORD PTR SS:[EBP-10]
004F5C4A 52 PUSH EDX
004F5C4B 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
004F5C4E 50 PUSH EAX
004F5C4F E8 4CFCFFFF CALL JPSKB061.004F58A0
004F5C54 83C4 14 ADD ESP,14
004F5C57 68 841B5000 PUSH JPSKB061.00501B84 ; imm32.dll
004F5C5C FF15 9C255000 CALL DWORD PTR DS:[50259C] ; kernel32.GetModuleHandleA
004F5C62 8945 EC MOV DWORD PTR SS:[EBP-14],EAX
004F5C65 837D EC 00 CMP DWORD PTR SS:[EBP-14],0
004F5C69 74 0E JE SHORT JPSKB061.004F5C79
004F5C6B 68 841B5000 PUSH JPSKB061.00501B84 ; imm32.dll
004F5C70 8B4D EC MOV ECX,DWORD PTR SS:[EBP-14]
004F5C73 51 PUSH ECX
004F5C74 E8 F7010000 CALL JPSKB061.004F5E70
004F5C79 8BE5 MOV ESP,EBP
004F5C7B 5D POP EBP
004F5C7C C3 RETN
总体看来,MoleBox解压程序前字串"EXECUTABLE"是个非常重要的标志,而在 VirtualProtect 函数上设断点,是个不错的选择。
二、捆绑文件
1、文件数目
要知道捆绑文件的数目,可以通过 BP GetFileTime 设断得到。以 Ultra Video Converter 为例,中断后取消断点Alt+F9返回:
00476C8C FF15 84364800 CALL DWORD PTR DS:[483684] ; kernel32.GetFileTime
00476C92 C745 AC 00000000 MOV DWORD PTR SS:[EBP-54],0 ; 返回到这里
00476C99 EB 09 JMP SHORT Ultra_Vi.00476CA4
00476C9B 8B4D AC MOV ECX,DWORD PTR SS:[EBP-54]
00476C9E 83C1 01 ADD ECX,1
00476CA1 894D AC MOV DWORD PTR SS:[EBP-54],ECX
00476CA4 8B55 AC MOV EDX,DWORD PTR SS:[EBP-54]
00476CA7 3B55 9C CMP EDX,DWORD PTR SS:[EBP-64] ; 这里[EBP-64]=1,就是捆绑文件的数目
00476CAA 0F83 E3000000 JNB Ultra_Vi.00476D93
00476CB0 8B45 AC MOV EAX,DWORD PTR SS:[EBP-54]
00476CB3 C1E0 04 SHL EAX,4
00476CB6 8B4D E0 MOV ECX,DWORD PTR SS:[EBP-20]
00476CB9 8B51 04 MOV EDX,DWORD PTR DS:[ECX+4]
00476CBC 8B4D DC MOV ECX,DWORD PTR SS:[EBP-24] ; [EBP-24]=003D2370,数据窗口中可以看到文件名
00476CBF 030C02 ADD ECX,DWORD PTR DS:[EDX+EAX]
00476CC2 8B55 AC MOV EDX,DWORD PTR SS:[EBP-54]
00476CC5 C1E2 04 SHL EDX,4
2、参与运行的可执行文件
对于参与运行的可执行文件,可以通过以下三个断点获取文件:
(1) BP CreateFileA,断下后看堆栈,根据堆栈显示信息改文件名(在 BP CreateFileA 之前,可以通过 BP GetCurrentProcessId 看到对捆绑文件更名的处理)。
(2) BP GetModuleHandleA,断下后取消断点(BP VirtualProtect 在对付捆绑文件时好像也很有功效,能得到OEP地址。有空再仔细研究)。
(3) 在参与执行的 DLL 代码段上设内存访问断点,到达OEP。
而在第二步时dump下来,文件的输入表都是未被填充过的。只要修正一下OEP,重定位表、输入表的RVA和大小,必要时修正一下基址,就OK了。
对于采用上面的第三步找OEP无效的文件,这时可以在上面的第一步后 BP GetSystemTimeAsFileTime,中断两次后ALT+F9返回(以下都以 MoleBoxPro_2.6.1.2387 主程序为例):
00436FE1 FF15 2C774400 CALL DWORD PTR DS:[44772C] ; kernel32.GetSystemTimeAsFileTime
00436FE7 8B45 C4 MOV EAX,DWORD PTR SS:[EBP-3C] ; 回到这里,[EBP-3C]中就是PE文件头
00436FEA 8B4D F0 MOV ECX,DWORD PTR SS:[EBP-10]
00436FED 64:890D 00000000 MOV DWORD PTR FS:[0],ECX
数据窗口中显示如下:
00D30098 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ?......��..
00D300A8 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ?......@.......
00D300B8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D300C8 00 00 00 00 00 00 00 00 00 00 00 00 E0 00 00 00 ............?..
00D300D8 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ?.???L?Th
00D300E8 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno
00D300F8 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS
00D30108 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$.......
00D30118 F5 7E EE 54 B1 1F 80 07 B1 1F 80 07 B1 1F 80 07 鮺頣? € ?€ ?€
00D30128 D3 00 93 07 B3 1F 80 07 32 03 8E 07 B3 1F 80 07 ???€ 2??€
00D30138 B1 1F 81 07 E6 1F 80 07 DE 00 8B 07 A3 1F 80 07 ???€ ???€
00D30148 DE 00 8A 07 95 1F 80 07 09 19 86 07 B0 1F 80 07 ???€ .??€
00D30158 DE 00 84 07 B5 1F 80 07 52 69 63 68 B1 1F 80 07 ???€ Rich?€
00D30168 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00D30178 50 45 00 00 4C 01 05 00 20 8E AB 39 00 00 00 00 PE..L. 帿9....
用 LordPE 或 PETools 的区域转存功能,把开始地址为00D30098,大小1000的内存数据dump下来,作为完整dump文件的PE头参考(注意:这里我们只要这个dump的PE头中的入口点信息,其它的不要。如果直接覆盖dump程序的PE头的话,会出错的)。现在在执行前面提到的第二步BP GetModuleHandleA,断下后dump程序,按前面说的修正主程序的那种找IAT的方法修正IAT,再填入正确的OEP、重定位表等。
--------------------------------------------------------------------------------------------------
关于从开始的时候设 BP VirtualProtect,对捆绑文件的作用:
0048494C FF15 2C074900 CALL DWORD PTR DS:[49072C] ; kernel32.VirtualProtect
00484952 8B15 04064900 MOV EDX,DWORD PTR DS:[490604]
00484958 8B45 E8 MOV EAX,DWORD PTR SS:[EBP-18]
0048495B 0342 08 ADD EAX,DWORD PTR DS:[EDX+8]
0048495E 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX
00484961 C705 94084900 00>MOV DWORD PTR DS:[490894],0
0048496B 6A 00 PUSH 0
0048496D 68 C4FB4800 PUSH Ultra_MP.0048FBC4 ; ASCII "EXECUTABLE"
00484972 8B0D 90084900 MOV ECX,DWORD PTR DS:[490890] ; Ultra_MP.00400110
00484978 51 PUSH ECX
00484979 8B55 E8 MOV EDX,DWORD PTR SS:[EBP-18]
0048497C 52 PUSH EDX
0048497D 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
00484980 50 PUSH EAX
00484981 E8 1AFBFFFF CALL Ultra_MP.004844A0 ; 这个CALL是关键,在这里处理捆绑文件
跟进上面那个关键的 CALL,一路F8会来到这个地方:
00484580 ^\E9 2EFFFFFF JMP Ultra_MP.004844B3
00484585 EB 20 JMP SHORT Ultra_MP.004845A7
00484587 8B4D DC MOV ECX,DWORD PTR SS:[EBP-24]
0048458A 51 PUSH ECX ; 要处理的DLL名称
0048458B E8 BB5C0000 CALL Ultra_MP.0048A24B ; 关键,这里处理捆绑DLL
00484590 8945 EC MOV DWORD PTR SS:[EBP-14],EAX
00484593 837D EC 00 CMP DWORD PTR SS:[EBP-14],0
00484597 75 0E JNZ SHORT Ultra_MP.004845A7
00484599 8B55 DC MOV EDX,DWORD PTR SS:[EBP-24]
0048459C 52 PUSH EDX
0048459D 68 D0FB4800 PUSH Ultra_MP.0048FBD0 ; ASCII "The dynamic link library '%s' could not be found"
004845A2 E8 1C370000 CALL Ultra_MP.00487CC3
004845A7 A1 C0FB4800 MOV EAX,DWORD PTR DS:[48FBC0]
004845AC 8945 E8 MOV DWORD PTR SS:[EBP-18],EAX
004845AF 8B4D 14 MOV ECX,DWORD PTR SS:[EBP+14]
004845B2 890D C0FB4800 MOV DWORD PTR DS:[48FBC0],ECX
004845B8 6A 00 PUSH 0
004845BA FF15 98064900 CALL DWORD PTR DS:[490698] ; kernel32.GetModuleHandleA
004845C0 3B45 0C CMP EAX,DWORD PTR SS:[EBP+C]
004845C3 75 67 JNZ SHORT Ultra_MP.0048462C
004845C5 C745 CC C4FB4800 MOV DWORD PTR SS:[EBP-34],Ultra_MP.0048FBC4 ; ASCII "EXECUTABLE"
004845CC 8B55 14 MOV EDX,DWORD PTR SS:[EBP+14]
004845CF 8955 C8 MOV DWORD PTR SS:[EBP-38],EDX
004845D2 8B45 C8 MOV EAX,DWORD PTR SS:[EBP-38]
跟进 0048458B 的那个 CALL,最后会看到这样的代码(一步步跟踪比较麻烦,我自己跟踪了一下,认为可能可以通过搜索对应命令序列来快速定位):
0048604F 6A 00 PUSH 0
00486051 6A 00 PUSH 0
00486053 8B85 74FFFFFF MOV EAX,DWORD PTR SS:[EBP-8C]
00486059 FF70 10 PUSH DWORD PTR DS:[EAX+10]
0048605C FF75 D4 PUSH DWORD PTR SS:[EBP-2C]
0048605F FF75 C4 PUSH DWORD PTR SS:[EBP-3C]
00486062 E8 0EB1FFFF CALL Ultra_MP.00481175
00486067 85C0 TEST EAX,EAX
00486069 74 06 JE SHORT Ultra_MP.00486071
0048606B 837D 9C 00 CMP DWORD PTR SS:[EBP-64],0
0048606F 75 0A JNZ SHORT Ultra_MP.0048607B
00486071 B9 0F0000EF MOV ECX,EF00000F
00486076 E8 931A0000 CALL Ultra_MP.00487B0E
0048607B 8B85 74FFFFFF MOV EAX,DWORD PTR SS:[EBP-8C]
00486081 8B4D CC MOV ECX,DWORD PTR SS:[EBP-34]
00486084 8948 14 MOV DWORD PTR DS:[EAX+14],ECX
00486087 8B85 74FFFFFF MOV EAX,DWORD PTR SS:[EBP-8C]
0048608D C740 24 400000C0 MOV DWORD PTR DS:[EAX+24],C0000040
00486094 E9 5A030000 JMP Ultra_MP.004863F3
00486099 8B85 74FFFFFF MOV EAX,DWORD PTR SS:[EBP-8C]
0048609F 8B8D 7CFFFFFF MOV ECX,DWORD PTR SS:[EBP-84]
004860A5 8B40 0C MOV EAX,DWORD PTR DS:[EAX+C]
004860A8 3B01 CMP EAX,DWORD PTR DS:[ECX]
004860AA 0F87 C7020000 JA Ultra_MP.00486377
004860B0 8B85 74FFFFFF MOV EAX,DWORD PTR SS:[EBP-8C]
004860B6 8B40 0C MOV EAX,DWORD PTR DS:[EAX+C]
004860B9 8B8D 74FFFFFF MOV ECX,DWORD PTR SS:[EBP-8C]
004860BF 0341 10 ADD EAX,DWORD PTR DS:[ECX+10]
004860C2 8B8D 7CFFFFFF MOV ECX,DWORD PTR SS:[EBP-84]
004860C8 3B01 CMP EAX,DWORD PTR DS:[ECX] ; 基址与IAT的RVA比较,这里直接在数据窗口中查看[ECX]的地址,可以看到完整的PE头。dump下来备用
004860CA 0F86 A7020000 JBE Ultra_MP.00486377
004860D0 83A5 60FFFFFF 00 AND DWORD PTR SS:[EBP-A0],0
004860D7 C745 FC 01000000 MOV DWORD PTR SS:[EBP-4],1
004860DE 6A 04 PUSH 4
004860E0 68 00100000 PUSH 1000
004860E5 8B85 74FFFFFF MOV EAX,DWORD PTR SS:[EBP-8C]
004860EB FF70 10 PUSH DWORD PTR DS:[EAX+10]
004860EE 6A 00 PUSH 0
004860F0 FF15 24074900 CALL DWORD PTR DS:[490724] ; kernel32.VirtualAlloc
004860F6 8985 60FFFFFF MOV DWORD PTR SS:[EBP-A0],EAX
004860FC 6A 00 PUSH 0
004860FE 6A 00 PUSH 0
00486100 8B85 74FFFFFF MOV EAX,DWORD PTR SS:[EBP-8C]
00486106 FF70 14 PUSH DWORD PTR DS:[EAX+14]
00486109 FF75 C4 PUSH DWORD PTR SS:[EBP-3C]
0048610C E8 0EA3FFFF CALL Ultra_MP.0048041F
搜索指令序列:
ADD EAX,DWORD PTR DS:[ECX+CONST]
MOV ECX,DWORD PTR SS:[EBP-CONST]
CMP EAX,DWORD PTR DS:[ECX]
上面是采用了模糊搜索,可能会找到几个,可以根据这个指令序列后面调用VirtualAlloc函数来定位。断下来后堆栈中可以看到确切的文件名。
注意:得到的PE头有可能区段的开始地址及大小有不正确的地方,粘贴了PE头后要自己在PE工具中看一下各个区段的地址和大小,有不正确的地方要自己修正一下。另外可能还要根据OD中所看到的模块基址的情况修正一下基址,否则重定位可能不正确。
3、运行某些功能才调用的文件
而对于运行程序某些功能才调用的的捆绑文件,还是采用 BP GetSystemTimeAsFileTime,断下后返回,在数据窗口中看数据,再在所看到的数据上设内存访问断点,F9运行,会被断下:
0043707D C1E9 02 SHR ECX,2
00437080 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ; 断在这里,EDI=001675D0,在数据窗口中跟随这个地址
00437082 8BC8 MOV ECX,EAX
00437084 83E1 03 AND ECX,3
00437087 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00437089 B8 00000100 MOV EAX,10000 ; UNICODE "=::=::\"
0043708E 2B45 F8 SUB EAX,DWORD PTR SS:[EBP-8]
00437091 3945 10 CMP DWORD PTR SS:[EBP+10],EAX ; [EBP+10]=00016200,文件大小
00437094 73 08 JNB SHORT mbox2w.0043709E
下面还有个地方继续复制,这里F8跟一下,等全部复制完,用 LordPE 或 PETools 的区域转存功能保存。
【版权声明】: 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!