- UID
- 5641
注册时间2005-12-22
阅读权限20
最后登录1970-1-1
以武会友
该用户从未签到
|
【文章标题】: UnpackMe_006 分析及脱壳
【文章作者】: RegKiller
【作者邮箱】: 都不用QQ了我也换
【作者QQ号】: 有缘分的论坛给我发短消息获取
【软件名称】: UnpackMe_006
【软件大小】: 很小
【下载地址】: 自己搜索下载
【加壳方式】: 未知壳
【保护方式】: 加壳保护
【编写语言】: MASM32 / TASM32
【操作平台】: 瘟系统都可以
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
考虑了一下,准备给新手详细说说这个文件的脱壳方法及思路,之前的分析在:
http://www.unpack.cn/viewthread. ... page%3D1&page=2
页的 39 楼,本文重新详细地写了分析及脱壳的过程,高手请自觉飘过,飘走之前务必给我加点分,再此先谢过各位朋友了,后面的动画教程由于我电脑比较烂,动画大家将就着看吧。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
【详细过程】
很久没发文了,现在人懒了,希望这篇文章可以给新手点思路,高手路过的也别忘了给我加点分,现在的论坛都要银子才能混啊,不搞收费下载了,没什么技术含量的东西。
- 先来个快速到达 OEP 方法,目的是让你先有点成功感,想了解为什么这么做,怎么知道要这么做的朋友可以看下面详细分析过程。
- 后面详细分析过程中我会用不同的方法来脱壳及修复,图文教程用了一种方法,动画中也略有不同,脚本中修复 IAT 又用了跟图文教程中也不一样的方法来修复 IAT。
- OD 载入程序后在 00401000 断下个"设置内存写入断点",SHIFT + F9 中断后删除刚才的断点。
- 然后再下一条指令 POP ESI 上下 F2 断点,中断后删除 F2 断点再在 00401000 断下个"设置内存写入断点"。
- 中断后删除刚才的断点,因为是 C 或汇编写的程序,所以下 bp GetModuleHandleA 后 SHIFT + F9 4 次就到 OEP 了。
- 这里断在 00401007 处,真正的 OEP 应该是 00401000。
复制代码
好了,我们开始:
1 首先查壳及文件是用什么语言编译的。
2 设置 OD 反调试
这里注意一下这项:Anti-RDTSC [基于驱动程序] 这个壳里有大量的 RDTSC 稍候我会简单说下这部分
3 找 OEP - 004059F2 > 55 PUSH EBP ; OD 载入后停在 EP 处
- 004059F3 8BEC MOV EBP,ESP
- 004059F5 83C4 F4 ADD ESP,-0C
- 004059F8 83C4 0C ADD ESP,0C
- 004059FB 50 PUSH EAX
- 004059FC EB 02 JMP SHORT 00405A00
- 004059FE 0000 ADD BYTE PTR DS:[EAX],AL
复制代码 下断 bp GetProcAddress+5 然后 F9 运行
(这里 +5 相当于在函数 GetProcAddress 入口后 5 字节下了断点,这样做的目的是避免壳检测,当然这里可以用其它方法,比如 +7 +9 或在 GetProcAddress 末尾的 RET 处下断,当然也可以直接用硬件断点下断)- 7C80AE40 kernel32.GetProcAddress 8BFF MOV EDI,EDI
- 7C80AE42 55 PUSH EBP
- 7C80AE43 8BEC MOV EBP,ESP
- 7C80AE45 51 PUSH ECX ; 断在这里
- 7C80AE46 51 PUSH ECX
- 7C80AE47 53 PUSH EBX
- 7C80AE48 57 PUSH EDI
复制代码 取消断点 ALT+F9 返回- 00950AA3 33DB XOR EBX,EBX ; 返回到这里
- 00950AA5 60 PUSHAD
- 00950AA6 EB 03 JMP SHORT 00950AAB
- 00950AA8 EB 03 JMP SHORT 00950AAD
- 00950AAA C7 ??? ; 未知命令
复制代码 Ctrl + F 查找 jmp eax 命令,然后在上面下断后 F9 运行
(这里简单说下找这个 jmp eax 命令是怎么来的,当我们上面 ALT +F9 返回后,可以用 F7 及 F8 单步跟踪,走到最后就是这个命令了。
当我们用 F7 及 F8 走的时候会遇到很多的 RDTSC 指令,这条指令会通过时间差来检测程序是否被调试,如果我们没开 OD 反调试插件里的 Anti-RDTSC [基于驱动程序],那么后面可能会遇到类似下面的代码:- 00940B42 83C4 04 ADD ESP,4
- 00940B45 85D2 TEST EDX,EDX
- 00940B47 ^ 75 D6 JNZ SHORT 00940B1F
- 00940B49 61 POPAD
复制代码 打开反调试插件后这个 JNZ 是应该不跳的,但我发现如果把 OD 晾在那很久后再遇到这样的代码,那么这个 JNZ 可能还会跳,这里可以手动 NOP 掉这行代码,或者在下一行代码处鼠标右键"在此处新建 EIP",也就相当与跳过了上面的代码,相对于 NOP 掉的好处是如果后面壳检测代码是否被修改了,那么我们可能就少走弯路了。
如果你很不幸跟着那个 JNZ 跳了,那么你会来到类似如下的指令处:- 00940B1F F0:0FC7C8 LOCK CMPXCHG8B EAX ; 非法使用寄存器
- 00940B23 EB 03 JMP SHORT 00940B28
- 00940B25 EB 03 JMP SHORT 00940B2A
- 00940B27 C7 ??? ; 未知命令
复制代码 估计很多新人都是挂在 LOCK CMPXCHG8B EAX 这条指令上了(偷笑中。。。),没关系,Ctrl + F2 重新来过,下次小心点OK了。
)- 009511D3 C40485 D275D661 LES EAX,FWORD PTR DS:[EAX*4+61D675D2]
- 009511DA 8B85 AD234000 MOV EAX,DWORD PTR SS:[EBP+4023AD]
- 009511E0 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX
- 009511E4 61 POPAD
- 009511E5 FFE0 JMP EAX ; 找到这里,在这句上下断
- 009511E7 60 PUSHAD
- 009511E8 8BF0 MOV ESI,EAX
- 009511EA 8BF9 MOV EDI,ECX
复制代码 断下后我们 F8 让程序跳到 EAX 所指定的地址 :00970000- 00970000 C7C7 72AFB4DF MOV EDI,DFB4AF72 ; 这下面可以一直 F8 大步走了
- 00970006 8D3D 5FBA581A LEA EDI,DWORD PTR DS:[1A58BA5F]
- 0097000C FFCF DEC EDI
- 0097000E 0FACF7 F2 SHRD EDI,ESI,0F2
- 00970012 0FBDFE BSR EDI,ESI
复制代码 。。。 中间代码省略,F8 一直走到底就是 OEP 了 。。。- 009707EB 8BFE MOV EDI,ESI
- 009707ED 19F7 SBB EDI,ESI
- 009707EF 6A 00 PUSH 0 ; 这里偷了 OEP 处的第一句的代码
- 009707F1 65:81E7 70E3980>AND EDI,398E370
- 009707F8 65:87FF XCHG EDI,EDI
- 009707FB F2: PREFIX REPNE:
复制代码 。。。 中间代码省略,F8 一直走到底就是 OEP 了 。。。- 00970C4A 69FE CB2BC651 IMUL EDI,ESI,51C62BCB
- 00970C50 85F7 TEST EDI,ESI
- 00970C52 F7C7 1CDC4C87 TEST EDI,874CDC1C
- 00970C58 81E7 43C67893 AND EDI,9378C643
- 00970C5E - E9 9F03A9FF JMP UnpackMe.00401002 ; 到 OEP 了
- 00970C63 0000 ADD BYTE PTR DS:[EAX],AL
- 00970C65 0000 ADD BYTE PTR DS:[EAX],AL
- 00970C67 0000 ADD BYTE PTR DS:[EAX],AL
- 00970C69 0000 ADD BYTE PTR DS:[EAX],AL
复制代码 (关于 009707EF PUSH 0 这条指令,这里我们有几种处理方法,如果你已经到 OEP 了,那么你会发现堆栈窗口中如下的代码:- 0012FF98 00000000
- 0012FF9C 00405A12 返回到 UnpackMe.00405A12 来自 UnpackMe.00405A36
- 0012FFA0 FFFFFFFF
- 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 窗口中的代码如下:- 00401002 E8 DB E8
- 00401003 F3 DB F3
- 00401004 0E DB 0E
- 00401005 00 DB 00
- 00401006 00 DB 00
- 00401007 A3 DB A3
- 00401008 4C DB 4C ; CHAR 'L'
- 00401009 36 DB 36 ; CHAR '6'
- 0040100A 40 DB 40 ; CHAR '@'
- 0040100B 00 DB 00
- 0040100C 6A DB 6A ; CHAR 'j'
- 0040100D 00 DB 00
- 0040100E 68 DB 68 ; CHAR 'h'
- 0040100F 66 DB 66 ; CHAR 'f'
- 00401010 10 DB 10
- 00401011 40 DB 40 ; CHAR '@'
- 00401012 00 DB 00
- 00401013 6A DB 6A ; CHAR 'j'
- 00401014 00 DB 00
- 00401015 68 DB 68 ; CHAR 'h'
复制代码 那么用鼠标右键菜单:分析->从模块删除分析就可以了,删除分析后代码如下:- 00401000 6A 00 PUSH 0 ; 这里就是 OEP 了
- 00401002 E8 F30E0000 CALL 00401EFA
- 00401007 A3 4C364000 MOV DWORD PTR DS:[40364C],EAX
- 0040100C 6A 00 PUSH 0
- 0040100E 68 66104000 PUSH 00401066
- 00401013 6A 00 PUSH 0
- 00401015 68 00304000 PUSH 00403000 ; ASCII "TESTWIN"
- 0040101A FF35 4C364000 PUSH DWORD PTR DS:[40364C]
- 00401020 E8 750E0000 CALL 00401E9A
- 00401025 50 PUSH EAX
- 00401026 E8 C30E0000 CALL 00401EEE
- 0040102B C3 RETN
- 0040102C 8925 803D4000 MOV DWORD PTR DS:[403D80],ESP
- 00401032 68 F4344000 PUSH 004034F4 ; ASCII "Unpack started..."
- 00401037 E8 9B020000 CALL 004012D7
- 0040103C E8 A9060000 CALL 004016EA
复制代码 )
4 关于 IAT 的修复
IAT的修复本例子有至少两种方法:
1 手工修复,2 写个脚本修复 3 找别人给你修复(不推荐但又是最省时间最省事的方法;) )。这里我们先看看代码后再考虑怎么修复
看下 00401002 E8 F30E0000 CALL 00401EFA 这句,回车进入代码如下:
00401EFA - FF25 C2039600 JMP DWORD PTR DS:[9603C2] 再回车进入- 009603C6 /EB 01 JMP SHORT 009603C9
- 009603C8 |C9 LEAVE
- 009603C9 \60 PUSHAD
- 009603CA 0F31 RDTSC
- 009603CC EB 01 JMP SHORT 009603CF
复制代码 下面很多类似的代码,看下这里有不少 RDTSC ,比如 009603CA 这行,避免继续 F7 挂掉,把 Olly Advanced 插件里的“反调试 II” 选项卡里的"Anti-RDTSC [基于驱动程序]"启用,选"方式1"就可以了。然后从 009603C6 这行 F7 往下走不远就看到 :- 009603F5 61 POPAD
- 009603F6 EB 01 JMP SHORT 009603F9
- 009603F8 C7 ??? ; 未知命令
- 009603F9 68 41B7807C PUSH kernel32.GetModuleHandleA ; 这就是我们要找的东西了
- 009603FE EB 01 JMP SHORT 00960401
- 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 运行程序,断下后来到这里:- 00940BFC A8 83 TEST AL,83
- 00940BFE C40485 D275D661 LES EAX,FWORD PTR DS:[EAX*4+61D675D2]
- 00940C05 8901 MOV DWORD PTR DS:[ECX],EAX
- 00940C07 83C7 04 ADD EDI,4 ; 中断后停在此处
- 00940C0A FECB DEC BL
- 00940C0C 58 POP EAX
- 00940C0D 80FB 00 CMP BL,0
复制代码 看下寄存器窗口中的数据- EAX 009503C2
- ECX 00401EFC UnpackMe.00401EFC
- EDX 7C99E178 ntdll.7C99E178
- EBX 00000001
- ESP 0012FF7C
- EBP 00004A00
- ESI 00970000
- EDI 00970124
- 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 配合着往下单步走:- 00940AA3 33DB XOR EBX,EBX
- 00940AA5 60 PUSHAD
- 00940AA6 EB 03 JMP SHORT 00940AAB
- 00940AA8 EB 03 JMP SHORT 00940AAD
- 00940AAA C7 ??? ; 未知命令
- 00940AAB ^ EB FB JMP SHORT 00940AA8
复制代码 从 00940AA3 处开始往下一直走,这里需要点耐心,如果遇到前天提到的那个 JNZ 记得别跟着跳过去,走到如下代码处:
过程中很多花指令,可以写个去花的东西,OD 有去花插件,而且本例程序不会检测,这里不多说了。- 00941568 83C4 04 ADD ESP,4
- 0094156B 85D2 TEST EDX,EDX
- 0094156D ^ 75 D6 JNZ SHORT 00941545 ; 这类 RDTSC 的检测全部都别跳
- 0094156F 61 POPAD
- 00941570 0385 B1234000 ADD EAX,DWORD PTR SS:[EBP+4023B1]
- 00941576 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX
- 0094157A E8 00000000 CALL 0094157F
- 0094157F 5B POP EBX
- 00941580 81C3 61020000 ADD EBX,261
- 00941586 8933 MOV DWORD PTR DS:[EBX],ESI ; 这里就关键代码了
- 00941588 8BF8 MOV EDI,EAX
- 0094158A 60 PUSHAD
- 0094158B EB 03 JMP SHORT 00941590
- 0094158D EB 03 JMP SHORT 00941592
- 0094158F C7 ??? ; 未知命令
复制代码 通过前面的单步分析我们得知 00941586 MOV DWORD PTR DS:[EBX],ESI 这里直接把 ESI 的值写入到 [EAX] 里,这里 [] 相当于把指定的值写入到指定寄存器中地址所指定的空间。假设 EBX 为 401000,ESI 为 200 那么过了这句后 ESI 中的 200 被传送到了 401000 这个地址中,而 EBX 的值还是原来的 401000,这里 [EBX] 其实是个指向 401000 的指针。
看下当前各寄存器的值:- EAX 00950000
- ECX 00401ED8 UnpackMe.00401ED8
- EDX 7C99E178 ntdll.7C99E178
- EBX 009417E0
- ESP 0012FF58
- EBP 00004A00
- ESI 77D18C2E user32.SetTimer
- EDI 00970018
- EIP 00941586
复制代码 ESI 中放的是正确的函数地址,EAX 就是我们希望写入的地址了,所以这里我们把 00941586 处的 MOV DWORD PTR DS:[EBX],ESI 改为 MOV DWORD PTR DS:[EAX],ESI,但只改这句还不行,后面我发现程序中还有两个地方又把 00950000 这里的内容修改掉了。
改好上面这句后我们继续 F7 及 F8 往下走,经过刚才修改过的那行代码后我们可以在数据窗口中 d 00950000 来观察写入的内容:- 00950000 77D18C2E user32.SetTimer
- 00950004 00000000
复制代码 继续往下走,直到走到下面的代码处:- 0094162A 85D2 TEST EDX,EDX
- 0094162C ^ 75 D6 JNZ SHORT 00941604 ; 检测调试器,不跳
- 0094162E 61 POPAD
- 0094162F 8BF3 MOV ESI,EBX
- 00941631 81EE 38000000 SUB ESI,38
- 00941637 B9 4A000000 MOV ECX,4A
- 0094163C FC CLD
- 0094163D F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; 关键代码
- 0094163F 8B85 A5234000 MOV EAX,DWORD PTR SS:[EBP+4023A5]
- 00941645 0385 B1234000 ADD EAX,DWORD PTR SS:[EBP+4023B1]
- 0094164B 60 PUSHAD
- 0094164C EB 03 JMP SHORT 00941651
复制代码 走到 0094163D REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 我们看下寄存器窗口中的内容:- EAX 00950000
- ECX 0000004A
- EDX 7C99E178 ntdll.7C99E178
- EBX 009417E0
- ESP 0012FF58
- EBP 00004A00
- ESI 009417A8
- EDI 00950000
- EIP 0094163D
复制代码 ESI 所指向的 009417A8 中是垃圾数据,EDI 中的值又是我们刚才刚刚修改代码后写入的正确函数,所以这句要 NOP 掉。
NOP 掉 0094163D 这行指令后继续往下走:- 00941792 83C4 04 ADD ESP,4
- 00941795 85D2 TEST EDX,EDX
- 00941797 ^ 75 D6 JNZ SHORT 0094176F ; 调试器检测
- 00941799 61 POPAD
- 0094179A 8918 MOV DWORD PTR DS:[EAX],EBX ; 关键代码
- 0094179C 8185 B1234000 4>ADD DWORD PTR SS:[EBP+4023B1],4A
- 009417A6 61 POPAD
- 009417A7 C3 RETN
- 009417A8 0000 ADD BYTE PTR DS:[EAX],AL
复制代码 来到 0094179A MOV DWORD PTR DS:[EAX],EBX 后看下寄存器窗口中的数据:- EAX 00950000
- ECX 0000004A
- EDX 7C99E178 ntdll.7C99E178
- EBX 00950004
- ESP 0012FF58
- EBP 00004A00
- ESI 009417A8
- EDI 00950000
- 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 分析一下代码,看到如下内容:- 00401000 . 6A 00 PUSH 0 ; /这里就是 OEP 了
- 00401002 . E8 F30E0000 CALL 00401EFA ; \GetModuleHandleA
- 00401007 . A3 4C364000 MOV DWORD PTR DS:[40364C],EAX
- 0040100C . 6A 00 PUSH 0 ; /lParam = NULL
- 0040100E . 68 66104000 PUSH 00401066 ; |DlgProc = UnpackMe.00401066
- 00401013 . 6A 00 PUSH 0 ; |hOwner = NULL
- 00401015 . 68 00304000 PUSH 00403000 ; |pTemplate = "TESTWIN"
- 0040101A . FF35 4C364000 PUSH DWORD PTR DS:[40364C] ; |hInst = NULL
- 00401020 . E8 750E0000 CALL 00401E9A ; \DialogBoxParamA
- 00401025 . 50 PUSH EAX ; /ExitCode
- 00401026 . E8 C30E0000 CALL 00401EEE ; \ExitProcess
- 0040102B . C3 RETN
- 0040102C /$ 8925 803D4000 MOV DWORD PTR DS:[403D80],ESP
- 00401032 |. 68 F4344000 PUSH 004034F4 ; ASCII "Unpack started..."
- 00401037 |. E8 9B020000 CALL 004012D7
- 0040103C |. E8 A9060000 CALL 004016EA
- 00401041 |. E8 7E0C0000 CALL 00401CC4
- 00401046 |. E8 8B060000 CALL 004016D6
- 0040104B |. E8 6F060000 CALL 004016BF
- 00401050 |. E8 46020000 CALL 0040129B
- 00401055 |. FF15 B8354000 CALL DWORD PTR DS:[4035B8]
- 0040105B |. 68 06354000 PUSH 00403506 ; ASCII "Unpack ended..."
- 00401060 |. E8 72020000 CALL 004012D7
- 00401065 \. C3 RETN
- 00401066 /. 55 PUSH EBP
- 00401067 |. 8BEC MOV EBP,ESP
- 00401069 |. 817D 0C 10010>CMP DWORD PTR SS:[EBP+C],110
- 00401070 |. 75 5B JNZ SHORT 004010CD
- 00401072 |. 68 08304000 PUSH 00403008 ; /lParam = 403008
- 00401077 |. 6A 00 PUSH 0 ; |wParam = 0
- 00401079 |. 6A 0C PUSH 0C ; |Message = WM_SETTEXT
- 0040107B |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; |hWnd
- 0040107E |. E8 470E0000 CALL 00401ECA ; \SendMessageA
- 00401083 |. 68 F4010000 PUSH 1F4 ; /RsrcName = 500.
- 00401088 |. FF35 4C364000 PUSH DWORD PTR DS:[40364C] ; |hInst = NULL
- 0040108E |. E8 2B0E0000 CALL 00401EBE ; \LoadIconA
复制代码 这里看到 CALL 函数都显示出来了。我们随便找个 CALL 上回车跟进:- 00401E8E $- FF25 78039500 JMP DWORD PTR DS:[950378] ; user32.wsprintfA
- 00401E94 $- FF25 2E039500 JMP DWORD PTR DS:[95032E] ; user32.CheckDlgButton
- 00401E9A $- FF25 E4029500 JMP DWORD PTR DS:[9502E4] ; user32.DialogBoxParamA
- 00401EA0 $- FF25 9A029500 JMP DWORD PTR DS:[95029A] ; user32.EndDialog
- 00401EA6 $- FF25 50029500 JMP DWORD PTR DS:[950250] ; user32.GetDlgItem
- 00401EAC $- FF25 06029500 JMP DWORD PTR DS:[950206] ; user32.IsDlgButtonChecked
- 00401EB2 $- FF25 BC019500 JMP DWORD PTR DS:[9501BC] ; user32.IsWindowVisible
- 00401EB8 $- FF25 72019500 JMP DWORD PTR DS:[950172] ; user32.KillTimer
- 00401EBE $- FF25 28019500 JMP DWORD PTR DS:[950128] ; user32.LoadIconA
- 00401EC4 $- FF25 DE009500 JMP DWORD PTR DS:[9500DE] ; user32.MessageBoxA
- 00401ECA $- FF25 94009500 JMP DWORD PTR DS:[950094] ; user32.SendMessageA
- 00401ED0 $- FF25 4A009500 JMP DWORD PTR DS:[95004A] ; user32.SetDlgItemTextA
- 00401ED6 $- FF25 00009500 JMP DWORD PTR DS:[950000] ; user32.SetTimer
- 00401EDC $- FF25 F0069500 JMP DWORD PTR DS:[9506F0] ; kernel32.CloseHandle
- 00401EE2 $- FF25 3A079500 JMP DWORD PTR DS:[95073A] ; kernel32.CreateFileA
- 00401EE8 $- FF25 84079500 JMP DWORD PTR DS:[950784] ; kernel32.CreateFileMappingA
- 00401EEE .- FF25 0C049500 JMP DWORD PTR DS:[95040C] ; kernel32.ExitProcess
- 00401EF4 $- FF25 CE079500 JMP DWORD PTR DS:[9507CE] ; kernel32.GetFileSize
- 00401EFA $- FF25 C2039500 JMP DWORD PTR DS:[9503C2] ; kernel32.GetModuleHandleA
- 00401F00 $- FF25 18089500 JMP DWORD PTR DS:[950818] ; kernel32.GetProcAddress
- 00401F06 $- FF25 A6069500 JMP DWORD PTR DS:[9506A6] ; kernel32.GetVersionExA
- 00401F0C $- FF25 5C069500 JMP DWORD PTR DS:[95065C] ; kernel32.LoadLibraryA
- 00401F12 $- FF25 12069500 JMP DWORD PTR DS:[950612] ; kernel32.MapViewOfFile
- 00401F18 $- FF25 C8059500 JMP DWORD PTR DS:[9505C8] ; kernel32.ReadProcessMemory
- 00401F1E $- FF25 7E059500 JMP DWORD PTR DS:[95057E] ; ntdll.RtlZeroMemory
- 00401F24 $- FF25 34059500 JMP DWORD PTR DS:[950534] ; kernel32.SetEndOfFile
- 00401F2A $- FF25 EA049500 JMP DWORD PTR DS:[9504EA] ; kernel32.SetFilePointer
- 00401F30 $- FF25 A0049500 JMP DWORD PTR DS:[9504A0] ; kernel32.UnmapViewOfFile
- 00401F36 $- FF25 56049500 JMP DWORD PTR DS:[950456] ; kernel32.lstrcpyA
- 00401F3C $- FF25 62089500 JMP DWORD PTR DS:[950862] ; comdlg32.GetOpenFileNameA
- 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
|