【文章标题】: 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 的区域转存功能保存。
  
--------------------------------------------------------------------------------
【版权声明】: 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!