飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 7186|回复: 22

[原创] 【每周一壳】【新手练习】UnpackMe_006【分析及脱壳-图文+动画】

[复制链接]

该用户从未签到

发表于 2009-5-16 23:54:53 | 显示全部楼层 |阅读模式
【文章标题】: UnpackMe_006 分析及脱壳
【文章作者】: RegKiller
【作者邮箱】: 都不用QQ了我也换
【作者QQ号】: 有缘分的论坛给我发短消息获取
【软件名称】: UnpackMe_006
【软件大小】: 很小
【下载地址】: 自己搜索下载
【加壳方式】: 未知壳
【保护方式】: 加壳保护
【编写语言】: MASM32 / TASM32
【操作平台】: 瘟系统都可以
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

考虑了一下,准备给新手详细说说这个文件的脱壳方法及思路,之前的分析在:

http://www.unpack.cn/viewthread. ... page%3D1&page=2

页的 39 楼,本文重新详细地写了分析及脱壳的过程,高手请自觉飘过,飘走之前务必给我加点分,再此先谢过各位朋友了,后面的动画教程由于我电脑比较烂,动画大家将就着看吧。

----------------------------------------------------------------------------------------------------------------------------------------------------------------
【详细过程】

很久没发文了,现在人懒了,希望这篇文章可以给新手点思路,高手路过的也别忘了给我加点分,现在的论坛都要银子才能混啊,不搞收费下载了,没什么技术含量的东西。

  1. 先来个快速到达 OEP 方法,目的是让你先有点成功感,想了解为什么这么做,怎么知道要这么做的朋友可以看下面详细分析过程。

  2. 后面详细分析过程中我会用不同的方法来脱壳及修复,图文教程用了一种方法,动画中也略有不同,脚本中修复 IAT 又用了跟图文教程中也不一样的方法来修复 IAT。



  3. OD 载入程序后在 00401000 断下个"设置内存写入断点",SHIFT + F9 中断后删除刚才的断点。

  4. 然后再下一条指令 POP ESI 上下 F2 断点,中断后删除 F2 断点再在 00401000 断下个"设置内存写入断点"。

  5. 中断后删除刚才的断点,因为是 C 或汇编写的程序,所以下 bp GetModuleHandleA 后 SHIFT + F9 4 次就到 OEP 了。

  6. 这里断在 00401007 处,真正的 OEP 应该是 00401000。
复制代码


好了,我们开始:

1 首先查壳及文件是用什么语言编译的。







2 设置 OD 反调试




这里注意一下这项:Anti-RDTSC [基于驱动程序] 这个壳里有大量的 RDTSC 稍候我会简单说下这部分

3 找 OEP
  1. 004059F2 >  55              PUSH EBP                                 ; OD 载入后停在 EP 处
  2. 004059F3    8BEC            MOV EBP,ESP
  3. 004059F5    83C4 F4         ADD ESP,-0C
  4. 004059F8    83C4 0C         ADD ESP,0C
  5. 004059FB    50              PUSH EAX
  6. 004059FC    EB 02           JMP SHORT 00405A00
  7. 004059FE    0000            ADD BYTE PTR DS:[EAX],AL
复制代码
下断 bp GetProcAddress+5 然后 F9 运行

(这里 +5 相当于在函数 GetProcAddress 入口后 5 字节下了断点,这样做的目的是避免壳检测,当然这里可以用其它方法,比如 +7 +9 或在 GetProcAddress 末尾的 RET 处下断,当然也可以直接用硬件断点下断)
  1. 7C80AE40 kernel32.GetProcAddress          8BFF            MOV EDI,EDI
  2. 7C80AE42                            55              PUSH EBP
  3. 7C80AE43                            8BEC            MOV EBP,ESP
  4. 7C80AE45                            51              PUSH ECX                                 ; 断在这里
  5. 7C80AE46                            51              PUSH ECX
  6. 7C80AE47                            53              PUSH EBX
  7. 7C80AE48                            57              PUSH EDI
复制代码
取消断点 ALT+F9 返回
  1. 00950AA3      33DB            XOR EBX,EBX                              ; 返回到这里
  2. 00950AA5      60              PUSHAD
  3. 00950AA6      EB 03           JMP SHORT 00950AAB
  4. 00950AA8      EB 03           JMP SHORT 00950AAD
  5. 00950AAA      C7              ???                                      ; 未知命令
复制代码
Ctrl + F 查找 jmp eax 命令,然后在上面下断后 F9 运行

(这里简单说下找这个 jmp eax 命令是怎么来的,当我们上面 ALT +F9 返回后,可以用 F7 及 F8 单步跟踪,走到最后就是这个命令了。
当我们用 F7 及 F8 走的时候会遇到很多的 RDTSC 指令,这条指令会通过时间差来检测程序是否被调试,如果我们没开 OD 反调试插件里的 Anti-RDTSC [基于驱动程序],那么后面可能会遇到类似下面的代码:
  1. 00940B42    83C4 04         ADD ESP,4
  2. 00940B45    85D2            TEST EDX,EDX
  3. 00940B47  ^ 75 D6           JNZ SHORT 00940B1F
  4. 00940B49    61              POPAD
复制代码
打开反调试插件后这个 JNZ 是应该不跳的,但我发现如果把 OD 晾在那很久后再遇到这样的代码,那么这个 JNZ 可能还会跳,这里可以手动 NOP 掉这行代码,或者在下一行代码处鼠标右键"在此处新建 EIP",也就相当与跳过了上面的代码,相对于 NOP 掉的好处是如果后面壳检测代码是否被修改了,那么我们可能就少走弯路了。

如果你很不幸跟着那个 JNZ 跳了,那么你会来到类似如下的指令处:
  1. 00940B1F    F0:0FC7C8       LOCK CMPXCHG8B EAX                       ; 非法使用寄存器
  2. 00940B23    EB 03           JMP SHORT 00940B28
  3. 00940B25    EB 03           JMP SHORT 00940B2A
  4. 00940B27    C7              ???                                      ; 未知命令
复制代码
估计很多新人都是挂在 LOCK CMPXCHG8B EAX 这条指令上了(偷笑中。。。),没关系,Ctrl + F2 重新来过,下次小心点OK了。
)
  1. 009511D3      C40485 D275D661 LES EAX,FWORD PTR DS:[EAX*4+61D675D2]
  2. 009511DA      8B85 AD234000   MOV EAX,DWORD PTR SS:[EBP+4023AD]
  3. 009511E0      894424 1C       MOV DWORD PTR SS:[ESP+1C],EAX
  4. 009511E4      61              POPAD
  5. 009511E5      FFE0            JMP EAX                                  ; 找到这里,在这句上下断
  6. 009511E7      60              PUSHAD
  7. 009511E8      8BF0            MOV ESI,EAX
  8. 009511EA      8BF9            MOV EDI,ECX
复制代码
断下后我们 F8 让程序跳到 EAX 所指定的地址 :00970000
  1. 00970000      C7C7 72AFB4DF   MOV EDI,DFB4AF72                         ; 这下面可以一直 F8 大步走了
  2. 00970006      8D3D 5FBA581A   LEA EDI,DWORD PTR DS:[1A58BA5F]
  3. 0097000C      FFCF            DEC EDI
  4. 0097000E      0FACF7 F2       SHRD EDI,ESI,0F2
  5. 00970012      0FBDFE          BSR EDI,ESI
复制代码
。。。 中间代码省略,F8 一直走到底就是 OEP 了 。。。
  1. 009707EB      8BFE            MOV EDI,ESI
  2. 009707ED      19F7            SBB EDI,ESI
  3. 009707EF      6A 00           PUSH 0                                ; 这里偷了 OEP 处的第一句的代码
  4. 009707F1      65:81E7 70E3980>AND EDI,398E370
  5. 009707F8      65:87FF         XCHG EDI,EDI
  6. 009707FB      F2:             PREFIX REPNE:
复制代码
。。。 中间代码省略,F8 一直走到底就是 OEP 了 。。。
  1. 00970C4A      69FE CB2BC651   IMUL EDI,ESI,51C62BCB
  2. 00970C50      85F7            TEST EDI,ESI
  3. 00970C52      F7C7 1CDC4C87   TEST EDI,874CDC1C
  4. 00970C58      81E7 43C67893   AND EDI,9378C643
  5. 00970C5E    - E9 9F03A9FF     JMP UnpackMe.00401002                    ; 到 OEP 了
  6. 00970C63      0000            ADD BYTE PTR DS:[EAX],AL
  7. 00970C65      0000            ADD BYTE PTR DS:[EAX],AL
  8. 00970C67      0000            ADD BYTE PTR DS:[EAX],AL
  9. 00970C69      0000            ADD BYTE PTR DS:[EAX],AL
复制代码
(关于 009707EF PUSH 0 这条指令,这里我们有几种处理方法,如果你已经到 OEP 了,那么你会发现堆栈窗口中如下的代码:
  1. 0012FF98   00000000
  2. 0012FF9C   00405A12  返回到 UnpackMe.00405A12 来自 UnpackMe.00405A36
  3. 0012FFA0   FFFFFFFF
  4. 0012FFA4   0012FFC0
复制代码
0012FF98   00000000 这里就是刚才 009707EF PUSH 0 过来的,程序本身是 MASM32 / TASM32 汇编语言写的-本文开始处查壳工具全都误报了,所以正确的 OEP 应该在 00401000 处。如何知道这程序本身是什么语言写的 1 有原始未加壳的程序 2 根据经验。刚好在这个程序上这两条我都有。稍候给你们份原版未加壳的大家研究下。

好了,我们通过鼠标右键菜单把 EIP 新建在 00401000 处,然后补上被偷掉的 PUSH 0 刚好是两个字节,这里注意一下,如果你现在这么做了,并且还要继续跟踪程序,那么记得先把堆栈 0012FF98   00000000 POP 出来,保持堆栈平衡是不只是个好习惯,通过鼠标右键完成。

如果你现在的 EIP 还在 009707EF 的 PUSH 0 处,也就是你还没到 OEP 呢,那么直接把这句 NOP 掉,或者把这条指令改成 mov edi,edi 相当于两个 NOP 了,也刚好是两个字节。然后去 00970C5E JMP 00401002 处直接把 JMP 00401002 改成 JMP 00401000 后到 OEP 处还原那句 PUSH 0 就可以免去 POP 掉堆栈 0012FF98   00000000 这个步骤了。

到 OEP 后如果 OD CPU 窗口中的代码如下:
  1. 00401002      E8            DB E8
  2. 00401003      F3            DB F3
  3. 00401004      0E            DB 0E
  4. 00401005      00            DB 00
  5. 00401006      00            DB 00
  6. 00401007      A3            DB A3
  7. 00401008      4C            DB 4C                                    ;  CHAR 'L'
  8. 00401009      36            DB 36                                    ;  CHAR '6'
  9. 0040100A      40            DB 40                                    ;  CHAR '@'
  10. 0040100B      00            DB 00
  11. 0040100C      6A            DB 6A                                    ;  CHAR 'j'
  12. 0040100D      00            DB 00
  13. 0040100E      68            DB 68                                    ;  CHAR 'h'
  14. 0040100F      66            DB 66                                    ;  CHAR 'f'
  15. 00401010      10            DB 10
  16. 00401011      40            DB 40                                    ;  CHAR '@'
  17. 00401012      00            DB 00
  18. 00401013      6A            DB 6A                                    ;  CHAR 'j'
  19. 00401014      00            DB 00
  20. 00401015      68            DB 68                                    ;  CHAR 'h'
复制代码
那么用鼠标右键菜单:分析->从模块删除分析就可以了,删除分析后代码如下:
  1. 00401000    6A 00           PUSH 0                                   ; 这里就是 OEP 了
  2. 00401002    E8 F30E0000     CALL 00401EFA
  3. 00401007    A3 4C364000     MOV DWORD PTR DS:[40364C],EAX
  4. 0040100C    6A 00           PUSH 0
  5. 0040100E    68 66104000     PUSH 00401066
  6. 00401013    6A 00           PUSH 0
  7. 00401015    68 00304000     PUSH 00403000                            ; ASCII "TESTWIN"
  8. 0040101A    FF35 4C364000   PUSH DWORD PTR DS:[40364C]
  9. 00401020    E8 750E0000     CALL 00401E9A
  10. 00401025    50              PUSH EAX
  11. 00401026    E8 C30E0000     CALL 00401EEE
  12. 0040102B    C3              RETN
  13. 0040102C    8925 803D4000   MOV DWORD PTR DS:[403D80],ESP
  14. 00401032    68 F4344000     PUSH 004034F4                            ; ASCII "Unpack started..."
  15. 00401037    E8 9B020000     CALL 004012D7
  16. 0040103C    E8 A9060000     CALL 004016EA
复制代码
)

4 关于 IAT 的修复

IAT的修复本例子有至少两种方法:

1 手工修复,2 写个脚本修复 3 找别人给你修复(不推荐但又是最省时间最省事的方法;) )。这里我们先看看代码后再考虑怎么修复

看下 00401002      E8 F30E0000     CALL 00401EFA  这句,回车进入代码如下:

00401EFA    - FF25 C2039600   JMP DWORD PTR DS:[9603C2] 再回车进入
  1. 009603C6     /EB 01           JMP SHORT 009603C9
  2. 009603C8     |C9              LEAVE
  3. 009603C9     \60              PUSHAD
  4. 009603CA      0F31            RDTSC
  5. 009603CC      EB 01           JMP SHORT 009603CF
复制代码
下面很多类似的代码,看下这里有不少 RDTSC ,比如 009603CA 这行,避免继续 F7 挂掉,把 Olly Advanced 插件里的“反调试 II” 选项卡里的"Anti-RDTSC [基于驱动程序]"启用,选"方式1"就可以了。然后从 009603C6 这行 F7 往下走不远就看到 :
  1. 009603F5      61              POPAD
  2. 009603F6      EB 01           JMP SHORT 009603F9
  3. 009603F8      C7              ???                                               ; 未知命令
  4. 009603F9      68 41B7807C     PUSH kernel32.GetModuleHandleA                    ; 这就是我们要找的东西了
  5. 009603FE      EB 01           JMP SHORT 00960401
  6. 00960400    - E9 C3EB01E9     JMP E997EFC8
复制代码
009603F9  PUSH kernel32.GetModuleHandleA ,壳用 PUSH 函数然后 RET 跳到这个函数的方法来访问函数。

在 CPU 窗口中先删除 OD 的分析,然后我们到数据窗口中看内容

在 CPU 窗口中的 00401EFA  - FF25 C2039500   JMP DWORD PTR DS:[9503C2] 上鼠标右键:跟随到数据窗口->选定内容,然后在数据窗口中鼠标右键:反汇编,这样我们可以在数据窗口中看到汇编代码。




我很想知道 JMP DWORD PTR DS:[9503C2] 里的 9503C2 这个地址是怎么来的,所以方法如下:

数据窗口中 00401EFA  - FF25 C2039500   JMP DWORD PTR DS:[9503C2]

地址是 401EFA 去掉前面的 JMP 指令也就是那个 FF25 那么正确的地址就是 401EFA + 2 = 401EFC

可以在 OD 的命令行中输入 D 401EFC,也可以不输入命令直接用鼠标在数据窗口中 CTRl + 键盘下箭头来单个字节地移动窗口中的数据显示,当然这方法在 OD 的 CPU 等窗口中也适用。




在数据窗口中 00401EFC C2 0395 RETN 9503 处鼠标右键:断点->硬件写入->Dword 下个写入断点,然后 Ctrl + F2 重新加载程序来看看程序什么时候把 00401EFA JMP DWORD PTR DS:[xxxxxxxx] 写入了 9503C2 这个地址。

重新载如程序后和开始一样,下 bp GetProcAddress+5 断点,断下后 ALT +F9 返回,刚才下了硬件写入断点,这里我们继续 Shift +F9 运行程序,断下后来到这里:
  1. 00940BFC    A8 83           TEST AL,83
  2. 00940BFE    C40485 D275D661 LES EAX,FWORD PTR DS:[EAX*4+61D675D2]
  3. 00940C05    8901            MOV DWORD PTR DS:[ECX],EAX
  4. 00940C07    83C7 04         ADD EDI,4                                ; 中断后停在此处
  5. 00940C0A    FECB            DEC BL
  6. 00940C0C    58              POP EAX
  7. 00940C0D    80FB 00         CMP BL,0
复制代码
看下寄存器窗口中的数据
  1. EAX 009503C2
  2. ECX 00401EFC UnpackMe.00401EFC
  3. EDX 7C99E178 ntdll.7C99E178
  4. EBX 00000001
  5. ESP 0012FF7C
  6. EBP 00004A00
  7. ESI 00970000
  8. EDI 00970124
  9. EIP 00940C07
复制代码
这里比较重要的就是 EAX 和 ECX 了。看看他们的值你就知道是 00940C05 MOV DWORD PTR DS:[ECX],EAX 也就是我们断下后的上一条指令写入的。

这里如果你有兴趣可以在 00940C05 行上下个硬件执行断点 Shift + F9 多跑几次研究一下。我说了这么多,其实这里都不是本例的重点,我只希望让大家能够了解修复 IAT 前如何分析程序操作 IAT 地址及内容的方法而已。

好了,我们开始修复 IAT 了,Ctrl + F2 重新载入程序,然后清掉你 OD 中的所有类型的断点,老办法,下 bp GetProcAddress+5 中断后 ALT + F9 返回。

还记得 RDTSC 这个检测吧,过检测的方法前面已经说了,这里不罗嗦了,我们 F7 及 F8 配合着往下单步走:
  1. 00940AA3    33DB            XOR EBX,EBX
  2. 00940AA5    60              PUSHAD
  3. 00940AA6    EB 03           JMP SHORT 00940AAB
  4. 00940AA8    EB 03           JMP SHORT 00940AAD
  5. 00940AAA    C7              ???                                      ; 未知命令
  6. 00940AAB  ^ EB FB           JMP SHORT 00940AA8
复制代码
从 00940AA3 处开始往下一直走,这里需要点耐心,如果遇到前天提到的那个 JNZ 记得别跟着跳过去,走到如下代码处:

过程中很多花指令,可以写个去花的东西,OD 有去花插件,而且本例程序不会检测,这里不多说了。
  1. 00941568    83C4 04         ADD ESP,4
  2. 0094156B    85D2            TEST EDX,EDX
  3. 0094156D  ^ 75 D6           JNZ SHORT 00941545                       ; 这类 RDTSC 的检测全部都别跳
  4. 0094156F    61              POPAD
  5. 00941570    0385 B1234000   ADD EAX,DWORD PTR SS:[EBP+4023B1]
  6. 00941576    894424 1C       MOV DWORD PTR SS:[ESP+1C],EAX
  7. 0094157A    E8 00000000     CALL 0094157F
  8. 0094157F    5B              POP EBX
  9. 00941580    81C3 61020000   ADD EBX,261
  10. 00941586    8933            MOV DWORD PTR DS:[EBX],ESI               ; 这里就关键代码了
  11. 00941588    8BF8            MOV EDI,EAX
  12. 0094158A    60              PUSHAD
  13. 0094158B    EB 03           JMP SHORT 00941590
  14. 0094158D    EB 03           JMP SHORT 00941592
  15. 0094158F    C7              ???                                      ; 未知命令
复制代码
通过前面的单步分析我们得知 00941586 MOV DWORD PTR DS:[EBX],ESI 这里直接把 ESI 的值写入到 [EAX] 里,这里 [] 相当于把指定的值写入到指定寄存器中地址所指定的空间。假设 EBX 为 401000,ESI 为 200 那么过了这句后 ESI 中的 200 被传送到了 401000 这个地址中,而 EBX 的值还是原来的 401000,这里 [EBX] 其实是个指向 401000 的指针。

看下当前各寄存器的值:
  1. EAX 00950000
  2. ECX 00401ED8 UnpackMe.00401ED8
  3. EDX 7C99E178 ntdll.7C99E178
  4. EBX 009417E0
  5. ESP 0012FF58
  6. EBP 00004A00
  7. ESI 77D18C2E user32.SetTimer
  8. EDI 00970018
  9. EIP 00941586
复制代码
ESI 中放的是正确的函数地址,EAX 就是我们希望写入的地址了,所以这里我们把 00941586 处的 MOV DWORD PTR DS:[EBX],ESI 改为 MOV DWORD PTR DS:[EAX],ESI,但只改这句还不行,后面我发现程序中还有两个地方又把 00950000 这里的内容修改掉了。

改好上面这句后我们继续 F7 及 F8 往下走,经过刚才修改过的那行代码后我们可以在数据窗口中 d 00950000 来观察写入的内容:
  1. 00950000  77D18C2E  user32.SetTimer
  2. 00950004  00000000
复制代码
继续往下走,直到走到下面的代码处:
  1. 0094162A    85D2            TEST EDX,EDX
  2. 0094162C  ^ 75 D6           JNZ SHORT 00941604                                 ; 检测调试器,不跳
  3. 0094162E    61              POPAD
  4. 0094162F    8BF3            MOV ESI,EBX
  5. 00941631    81EE 38000000   SUB ESI,38
  6. 00941637    B9 4A000000     MOV ECX,4A
  7. 0094163C    FC              CLD
  8. 0094163D    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]       ; 关键代码
  9. 0094163F    8B85 A5234000   MOV EAX,DWORD PTR SS:[EBP+4023A5]
  10. 00941645    0385 B1234000   ADD EAX,DWORD PTR SS:[EBP+4023B1]
  11. 0094164B    60              PUSHAD
  12. 0094164C    EB 03           JMP SHORT 00941651
复制代码
走到 0094163D REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 我们看下寄存器窗口中的内容:
  1. EAX 00950000
  2. ECX 0000004A
  3. EDX 7C99E178 ntdll.7C99E178
  4. EBX 009417E0
  5. ESP 0012FF58
  6. EBP 00004A00
  7. ESI 009417A8
  8. EDI 00950000
  9. EIP 0094163D
复制代码
ESI 所指向的 009417A8 中是垃圾数据,EDI 中的值又是我们刚才刚刚修改代码后写入的正确函数,所以这句要 NOP 掉。

NOP 掉 0094163D 这行指令后继续往下走:
  1. 00941792    83C4 04         ADD ESP,4
  2. 00941795    85D2            TEST EDX,EDX
  3. 00941797  ^ 75 D6           JNZ SHORT 0094176F                                 ; 调试器检测
  4. 00941799    61              POPAD
  5. 0094179A    8918            MOV DWORD PTR DS:[EAX],EBX                         ; 关键代码
  6. 0094179C    8185 B1234000 4>ADD DWORD PTR SS:[EBP+4023B1],4A
  7. 009417A6    61              POPAD
  8. 009417A7    C3              RETN
  9. 009417A8    0000            ADD BYTE PTR DS:[EAX],AL
复制代码
来到 0094179A MOV DWORD PTR DS:[EAX],EBX 后看下寄存器窗口中的数据:
  1. EAX 00950000
  2. ECX 0000004A
  3. EDX 7C99E178 ntdll.7C99E178
  4. EBX 00950004
  5. ESP 0012FF58
  6. EBP 00004A00
  7. ESI 009417A8
  8. EDI 00950000
  9. EIP 0094179A
复制代码
这里 EBX 的值就是我们未修复 IAT 前到 OEP 后 CALL 函数中的 JMP DWORD PTR DS:[xxxxxxxx] 中的值了。程序这里要把我们写好的正确地址再次写如垃圾,所以这句也 NOP 掉你就离脱壳越来越近了。

把 0094179A MOV DWORD PTR DS:[EAX],EBX 这句 NOP 掉后清除所有类型的断点,然后 Ctrl + F 查找 JMP EAX 命令,找到后在这条命令上下个断点,然后用前面的方法就可以到 OEP 了。到 OEP 后 Ctrl + A 分析一下代码,看到如下内容:
  1. 00401000   .  6A 00         PUSH 0                               ; /这里就是 OEP 了
  2. 00401002   .  E8 F30E0000   CALL 00401EFA                        ; \GetModuleHandleA
  3. 00401007   .  A3 4C364000   MOV DWORD PTR DS:[40364C],EAX
  4. 0040100C   .  6A 00         PUSH 0                               ; /lParam = NULL
  5. 0040100E   .  68 66104000   PUSH 00401066                        ; |DlgProc = UnpackMe.00401066
  6. 00401013   .  6A 00         PUSH 0                               ; |hOwner = NULL
  7. 00401015   .  68 00304000   PUSH 00403000                        ; |pTemplate = "TESTWIN"
  8. 0040101A   .  FF35 4C364000 PUSH DWORD PTR DS:[40364C]           ; |hInst = NULL
  9. 00401020   .  E8 750E0000   CALL 00401E9A                        ; \DialogBoxParamA
  10. 00401025   .  50            PUSH EAX                             ; /ExitCode
  11. 00401026   .  E8 C30E0000   CALL 00401EEE                        ; \ExitProcess
  12. 0040102B   .  C3            RETN
  13. 0040102C  /$  8925 803D4000 MOV DWORD PTR DS:[403D80],ESP
  14. 00401032  |.  68 F4344000   PUSH 004034F4                        ;  ASCII "Unpack started..."
  15. 00401037  |.  E8 9B020000   CALL 004012D7
  16. 0040103C  |.  E8 A9060000   CALL 004016EA
  17. 00401041  |.  E8 7E0C0000   CALL 00401CC4
  18. 00401046  |.  E8 8B060000   CALL 004016D6
  19. 0040104B  |.  E8 6F060000   CALL 004016BF
  20. 00401050  |.  E8 46020000   CALL 0040129B
  21. 00401055  |.  FF15 B8354000 CALL DWORD PTR DS:[4035B8]
  22. 0040105B  |.  68 06354000   PUSH 00403506                        ;  ASCII "Unpack ended..."
  23. 00401060  |.  E8 72020000   CALL 004012D7
  24. 00401065  \.  C3            RETN
  25. 00401066  /.  55            PUSH EBP
  26. 00401067  |.  8BEC          MOV EBP,ESP
  27. 00401069  |.  817D 0C 10010>CMP DWORD PTR SS:[EBP+C],110
  28. 00401070  |.  75 5B         JNZ SHORT 004010CD
  29. 00401072  |.  68 08304000   PUSH 00403008                        ; /lParam = 403008
  30. 00401077  |.  6A 00         PUSH 0                               ; |wParam = 0
  31. 00401079  |.  6A 0C         PUSH 0C                              ; |Message = WM_SETTEXT
  32. 0040107B  |.  FF75 08       PUSH DWORD PTR SS:[EBP+8]            ; |hWnd
  33. 0040107E  |.  E8 470E0000   CALL 00401ECA                        ; \SendMessageA
  34. 00401083  |.  68 F4010000   PUSH 1F4                             ; /RsrcName = 500.
  35. 00401088  |.  FF35 4C364000 PUSH DWORD PTR DS:[40364C]           ; |hInst = NULL
  36. 0040108E  |.  E8 2B0E0000   CALL 00401EBE                        ; \LoadIconA
复制代码
这里看到 CALL 函数都显示出来了。我们随便找个 CALL 上回车跟进:
  1. 00401E8E   $- FF25 78039500 JMP DWORD PTR DS:[950378]            ;  user32.wsprintfA
  2. 00401E94   $- FF25 2E039500 JMP DWORD PTR DS:[95032E]            ;  user32.CheckDlgButton
  3. 00401E9A   $- FF25 E4029500 JMP DWORD PTR DS:[9502E4]            ;  user32.DialogBoxParamA
  4. 00401EA0   $- FF25 9A029500 JMP DWORD PTR DS:[95029A]            ;  user32.EndDialog
  5. 00401EA6   $- FF25 50029500 JMP DWORD PTR DS:[950250]            ;  user32.GetDlgItem
  6. 00401EAC   $- FF25 06029500 JMP DWORD PTR DS:[950206]            ;  user32.IsDlgButtonChecked
  7. 00401EB2   $- FF25 BC019500 JMP DWORD PTR DS:[9501BC]            ;  user32.IsWindowVisible
  8. 00401EB8   $- FF25 72019500 JMP DWORD PTR DS:[950172]            ;  user32.KillTimer
  9. 00401EBE   $- FF25 28019500 JMP DWORD PTR DS:[950128]            ;  user32.LoadIconA
  10. 00401EC4   $- FF25 DE009500 JMP DWORD PTR DS:[9500DE]            ;  user32.MessageBoxA
  11. 00401ECA   $- FF25 94009500 JMP DWORD PTR DS:[950094]            ;  user32.SendMessageA
  12. 00401ED0   $- FF25 4A009500 JMP DWORD PTR DS:[95004A]            ;  user32.SetDlgItemTextA
  13. 00401ED6   $- FF25 00009500 JMP DWORD PTR DS:[950000]            ;  user32.SetTimer
  14. 00401EDC   $- FF25 F0069500 JMP DWORD PTR DS:[9506F0]            ;  kernel32.CloseHandle
  15. 00401EE2   $- FF25 3A079500 JMP DWORD PTR DS:[95073A]            ;  kernel32.CreateFileA
  16. 00401EE8   $- FF25 84079500 JMP DWORD PTR DS:[950784]            ;  kernel32.CreateFileMappingA
  17. 00401EEE   .- FF25 0C049500 JMP DWORD PTR DS:[95040C]            ;  kernel32.ExitProcess
  18. 00401EF4   $- FF25 CE079500 JMP DWORD PTR DS:[9507CE]            ;  kernel32.GetFileSize
  19. 00401EFA   $- FF25 C2039500 JMP DWORD PTR DS:[9503C2]            ;  kernel32.GetModuleHandleA
  20. 00401F00   $- FF25 18089500 JMP DWORD PTR DS:[950818]            ;  kernel32.GetProcAddress
  21. 00401F06   $- FF25 A6069500 JMP DWORD PTR DS:[9506A6]            ;  kernel32.GetVersionExA
  22. 00401F0C   $- FF25 5C069500 JMP DWORD PTR DS:[95065C]            ;  kernel32.LoadLibraryA
  23. 00401F12   $- FF25 12069500 JMP DWORD PTR DS:[950612]            ;  kernel32.MapViewOfFile
  24. 00401F18   $- FF25 C8059500 JMP DWORD PTR DS:[9505C8]            ;  kernel32.ReadProcessMemory
  25. 00401F1E   $- FF25 7E059500 JMP DWORD PTR DS:[95057E]            ;  ntdll.RtlZeroMemory
  26. 00401F24   $- FF25 34059500 JMP DWORD PTR DS:[950534]            ;  kernel32.SetEndOfFile
  27. 00401F2A   $- FF25 EA049500 JMP DWORD PTR DS:[9504EA]            ;  kernel32.SetFilePointer
  28. 00401F30   $- FF25 A0049500 JMP DWORD PTR DS:[9504A0]            ;  kernel32.UnmapViewOfFile
  29. 00401F36   $- FF25 56049500 JMP DWORD PTR DS:[950456]            ;  kernel32.lstrcpyA
  30. 00401F3C   $- FF25 62089500 JMP DWORD PTR DS:[950862]            ;  comdlg32.GetOpenFileNameA
  31. 00401F42   $- FF25 AC089500 JMP DWORD PTR DS:[9508AC]            ;  shell32.DragQueryFileA
复制代码
JMP 函数也全是正确的了。在 00401000 处用 LoadPE 转存,此时用 Import REConstructor 还不能修复 IAT ,原因是这里函数名地址的对齐是不正确的。乱序,如果你用 Import REConstructor 把所有错误的指针全部剪切掉,那么程序修复后会丢失部分指针。如下图:





这样修复脱壳后的程序修复后是肯定无法执行的。这里我们先用 Universal Import Fixer 来重建一张 IAT 表出来。然后再用 Import REConstructor 去修复转存文件。

在 OD 菜单中:文件->挂接,在弹出的窗口中找红色的那行就是当前进程了,我这里当前进程的PID(这里是16进制的)是 0x1400




在 Universal Import Fixer 的 Process ID 中输入 1400 把后面的 Hex 打钩,因为是 16 进制的

在 OD 窗口总点 M 按钮,或者打开查看菜单中的内存,快捷键是 Alt + M,这里看一下当前进程的代码起始地址和结束地址,我这里的起始地址是:401000 结束地址是 404000 这个段的大小是 4000,那么在 Universal Import Fixer 的 Code Star:中输入 401000 Code End:中输入 404000 + 4000 也就是 408000



New Iat Va 这里我们先在 OD 中用内存插件分配一块内存用来保存新的 IAT,Universal Import Fixer 手册中说 Code Star Code End 和 New Iat Va 如果输入 0 那么 Universal Import Fixer 会自动为你查找及分配,不过有些时候尤其是脱壳的时候可能成功几率比较小,所以我们全手动指定比较准确一点。

这里我在 OD 中分配了地址为:10400000 大小为:1000 的内存空间。指定 10400000 这个地址是为了一会在 Import REConstructor 中填写地址直接减掉 00400000 这个 Image Base,没让 Universal Import Fixer 自动分配也是因为我现在懒的计算了。一会直接写如 10000000 就 OK 了,输入全都输入后点 Start 开始重建输入表了,点 Start 之前你可以在 OD 的数据窗口中:d 10400000 来观看重建的输入表。






重建后在 Import REConstructor 中添入正确的地址就可以了,我这里:

OEP:00001000
RVA:10000000
SIZE:00000088




修正转存后 PEID 再查就显示为:MASM32 / TASM32 了。



----------------------------------------------------------------------------------------------------------------------------------------------------------------
【版权声明】: 本文原创于UnPacKcN论坛及看雪技术论坛等,论坛排名不分先后, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年05月16日 5:29:43

脱壳动画网盘下载 - 任选一个就可以:

http://www.namipan.com/d/UnPackM ... 1e312a97473d89b7c00

http://www.vdisk.cn/go/index?3571667A3901

http://www.brsbox.com/filebox/do ... 71a56a9dd0775285bbd

不想看动画的朋友也可以直接下载下面的附件,附件中有脱壳脚本,不过脚本在修复 IAT 的时候使用的是到 OEP 后的另一种修复方法:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入我们

x
PYG19周年生日快乐!

该用户从未签到

发表于 2009-5-17 00:26:42 | 显示全部楼层
谢谢了   呵呵 好东西
PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    2018-3-5 11:37
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2009-5-20 17:48:57 | 显示全部楼层
    olly advanced插件哪儿找的汉化版?
    PYG19周年生日快乐!

    该用户从未签到

     楼主| 发表于 2009-5-21 23:00:48 | 显示全部楼层
    原帖由 hdy981 于 2009-5-20 17:48 发表
    olly advanced插件哪儿找的汉化版?


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?加入我们

    x
    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    2020-4-10 17:02
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2009-5-22 10:02:26 | 显示全部楼层
    我来顶深南。。。。。。大盗
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2009-5-22 17:59:37 | 显示全部楼层
    提示: 作者被禁止或删除 内容自动屏蔽
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2009-6-6 23:47:44 | 显示全部楼层
    我也顶下 哥们儿
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2009-6-7 08:27:26 | 显示全部楼层
    看代码犹如天书,看来要好好学习了!
    PYG19周年生日快乐!
  • TA的每日心情
    无聊
    2017-11-20 21:35
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2009-6-18 06:45:07 | 显示全部楼层
    /:good 顶起。。不错的东东
    PYG19周年生日快乐!
  • TA的每日心情

    2021-3-15 02:34
  • 签到天数: 347 天

    [LV.8]以坛为家I

    发表于 2010-2-19 22:02:48 | 显示全部楼层
    支持下,学习了。
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表