首页
社区
课程
招聘
[转帖]MoleBox 脱壳的一些总结
发表于: 2007-12-14 21:51 4593

[转帖]MoleBox 脱壳的一些总结

2007-12-14 21:51
4593
论坛上写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?......
本帖转自青岛智洋学院:
http://teamsourcing.com.cn/bbs转载注明出处

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 44229
活跃值: (19955)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
[quote=luzechao;391990]本帖转自青岛智洋学院:
http://teamsourcing.com.cn/bbs转载注明出处[/quote]

原文出自本论坛,文章到外面转了一圈就成了别人的,无语了。。。

标 题: MoleBox 脱壳的一些总结
作 者: CCDebuger
时 间: 2007-04-14,09:41
链 接: http://bbs.pediy.com/showthread.php?t=42700
2007-12-14 21:57
0
游客
登录 | 注册 方可回帖
返回
//