【文章标题】: 一个PESpin保护程序脱壳调试报告
【文章作者】: eJamse
【下载地址】: 见附件(目标extdfx169.exe、dumped_extdfx169.exe、PESpin 1.x - Code Fixer.txt)
【加壳方式】: PESpin
【使用工具】: OD PEID LordPE ImportRec UIF ResEdit-x86 破解计算器
【操作平台】: 虚拟机WinXP sp3
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
PEID查壳,显示为“PESpin 0.3x - 1.xx -> cyberbob”。双击文件运行,打开任务管理器发现只有一个进程。用OD载入文件,开始我们的脱壳之旅。
一、Рикардо Нарваха(RicardoNarvaja李嘉图纳尔瓦哈)分析法(由点突破,恢复IAT及IAT2):
1、ESP定律结合M镜像401000处F2下断找到OEP=004032D6(以后可以HE 004032D6直接运行到OEP):
或者OD载入目标extdfx169.exe,忽略所有异常,单步F7两次,ESP变红,下硬件断点,F9两次,停在
00416ADA F7D2 not edx ; ntdll.KiFastSystemCallRet
查看前面一句,是:
00416AD9 61 popad
或者OD载入目标extdfx169.exe,忽略所有异常,单步F7两次,ESP变红,下硬件断点,F9两次,停在
00416ADA F7D2 not edx ; ntdll.KiFastSystemCallRet
查看前面一句,是:
00416AD9 61 popad
2、此时(壳已经解码完成)找到两个关键点以便下硬件执行断点HE(下面会介绍由来):
二进制搜索89 07 EB 02 02 F5 F9找到关键点
00416010 8907 mov dword ptr ds:[edi],eax
00416012 EB 02 jmp short extdfx16.00416016
00416014 02F5 add dh,ch
00416016 F9 stc
也可以直接二进制搜索897424 1C找到另一关键点:
00415BC4 897424 1C mov dword ptr ss:[esp+1C],esi
二进制搜索89 07 EB 02 02 F5 F9找到关键点
00416010 8907 mov dword ptr ds:[edi],eax
00416012 EB 02 jmp short extdfx16.00416016
00416014 02F5 add dh,ch
00416016 F9 stc
也可以直接二进制搜索897424 1C找到另一关键点:
00415BC4 897424 1C mov dword ptr ss:[esp+1C],esi
3、找到IAT及IAT2:
按“C”钮回到00416ADA,继续单步F7到OEP=004032D6(没有偷代码),
查找模块间的直接调用,随便找一项
00401019 call extdfx16.00407B3E 目标=COMCTL32.DefSubclassProc
跟随得出ds:[00408000]=77192041 (COMCTL32.DefSubclassProc)
定位输入表范围
00401019 call extdfx16.00407B3E 目标=COMCTL32.DefSubclassProc
跟随得出ds:[00408000]=77192041 (COMCTL32.DefSubclassProc)
定位输入表范围
IAT=00408000-00408188...(数据窗口00408000跟随为77192041)
查找模块间的间接调用,随便找一项
00401028 call dword ptr ds:[4195F3] 目标=ds:[004195F3]=0095094F
逐步跟随得出调用的是USER32.77D2993A
00401028 call dword ptr ds:[4195F3] 目标=ds:[004195F3]=0095094F
逐步跟随得出调用的是USER32.77D2993A
重定位IAT2范围
IAT2=0041945D-00419852...(数据窗口004195F3跟随为0095094F,揪住不放,由点突破,进行下一步)
4、修复IAT及IAT2:
删除所有断点,再HW 004195F3并重启OD,多次F9运行程序
当数据窗口004195F3为0095094F时,排除混淆找到
00416010 8907 mov dword ptr ds:[edi],eax ;由0041600A处jmp来
00416012 /EB 02 jmp short extdfx16.00416016
00416010 8907 mov dword ptr ds:[edi],eax ;由0041600A处jmp来
00416012 /EB 02 jmp short extdfx16.00416016
HE 00416010再多次F9运行,观察数据窗口IAT2、寄存器窗口的变化
重启OD并F9运行(第一次F9后数据窗口跟随004195F3),数据窗口定位004195F3的前一行004195E3,继续多次F9,
直到004195EE(004195F3的前一项)还没被写入00950935时停下,Ctrl+T设置自动跟踪的条件:
(当然也可以删除所有断点,HW 004195EE后重启OD并F9运行到断下,数据窗口跟随004195EE直到ds:[004195EE]=00950935)
EAX==0095094F||EBX==0095094F||ECX==0095094F||EDX==0095094F||ESI==0095094F||EDI==0095094F
删除所有断点Ctrl+F11跟踪进入,直到停在,
EAX==0095094F||EBX==0095094F||ECX==0095094F||EDX==0095094F||ESI==0095094F||EDI==0095094F
删除所有断点Ctrl+F11跟踪进入,直到停在,
00415BC4 897424 1C mov dword ptr ss:[esp+1C],esi
00415BC4 897424 1C mov dword ptr ss:[esp+1C],esi
改变跟踪条件,观察77D2993A首次出现的地方
EAX==77D2993A||EBX==77D2993A||ECX==77D2993A||EDX==77D2993A||ESI==77D2993A||EDI==77D2993A
继续跟踪,停在
EAX==77D2993A||EBX==77D2993A||ECX==77D2993A||EDX==77D2993A||ESI==77D2993A||EDI==77D2993A
继续跟踪,停在
00415CAB 8BC6 mov eax,esi ; USER32.77D2993A
00415CAB 8BC6 mov eax,esi ; USER32.77D2993A
删除所有断点,重新HE 00416010及HE 00415BC4,重启OD并F9运行,停在
00415BC4 897424 1C mov dword ptr ss:[esp+1C],esi
改成
00415BC4 894424 1C mov dword ptr ss:[esp+1C],eax
00415BC4 897424 1C mov dword ptr ss:[esp+1C],esi
改成
00415BC4 894424 1C mov dword ptr ss:[esp+1C],eax
继续F9,停在
00416010 8907 mov dword ptr ds:[edi],eax
改成
0041600A 90 nop
0041600B 90 nop
0041600C 90 nop
0041600D 90 nop
0041600E 8902 mov dword ptr ds:[edx],eax
00416010 8907 mov dword ptr ds:[edi],eax
00416010 8907 mov dword ptr ds:[edi],eax
改成
0041600A 90 nop
0041600B 90 nop
0041600C 90 nop
0041600D 90 nop
0041600E 8902 mov dword ptr ds:[edx],eax
00416010 8907 mov dword ptr ds:[edi],eax
删除所有断点,打开M内存镜像,在401000处F2下断,F9来到OEP=004032D6处,
数据窗口观察IAT及IAT2已恢复(上面这步打酱油的,主要学习他的分析方法,得个感性认识)
二、ximo(徐超)脱壳方法(API处理):
重启OD后HE 00416010并F9运行到断下来,注意堆栈:
$-3C > 7C865C8B kernel32.7C865C8B
$-38 > 0000000C
00416010 8907 mov dword ptr ds:[edi],eax
00416012 EB 02 jmp short extdfx16.00416016
00416014 02F5 add dh,ch
00416016 F9 stc
patch如下代码:
00416010 - E9 EB9F5400 jmp 00960000
00416015 90 nop
00416016 F9 stc
00960000 8B4424 C4 mov eax,dword ptr ss:[esp-3C]
00960004 2B4424 C8 sub eax,dword ptr ss:[esp-38]
00960008 8907 mov dword ptr ds:[edi],eax
0096000A - E9 0760ABFF jmp extdfx16.00416016
8B 44 24 C4 2B 44 24 C8 89 07 E9 07 60 AB FF
$-3C > 7C865C8B kernel32.7C865C8B
$-38 > 0000000C
00416010 8907 mov dword ptr ds:[edi],eax
00416012 EB 02 jmp short extdfx16.00416016
00416014 02F5 add dh,ch
00416016 F9 stc
patch如下代码:
00416010 - E9 EB9F5400 jmp 00960000
00416015 90 nop
00416016 F9 stc
00960000 8B4424 C4 mov eax,dword ptr ss:[esp-3C]
00960004 2B4424 C8 sub eax,dword ptr ss:[esp-38]
00960008 8907 mov dword ptr ds:[edi],eax
0096000A - E9 0760ABFF jmp extdfx16.00416016
8B 44 24 C4 2B 44 24 C8 89 07 E9 07 60 AB FF
删除所有断点,打开M镜像00401000处F2下断,F9运行,到达OEP=004032D6
右键查找所有模块间调用,发现所有API都回来了,除了这里
00401950 FF15 56984100 call dword ptr ds:[419856]
ds:[00419856]=00930000这里壳解码子程序到临时空间00930000
00401950 FF15 56984100 call dword ptr ds:[419856]
ds:[00419856]=00930000这里壳解码子程序到临时空间00930000
跟随找到子程序,以备后用(脱壳后怕有功能缺失,原程序点击图片会访问网站,我这里已经失效变成关闭功能了)
00930003 9C pushfd
00930007 60 pushad
00930008 8B4424 24 mov eax,dword ptr ss:[esp+24]
0093000C 8B08 mov ecx,dword ptr ds:[eax]
0093000E 8D78 04 lea edi,dword ptr ds:[eax+4]
00930011 897C24 24 mov dword ptr ss:[esp+24],edi
00930015 81E9 CDEF041F sub ecx,1F04EFCD
0093001B FC cld
00930028 8A07 mov al,byte ptr ds:[edi]
00930030 C0C0 95 rol al,95
00930033 90 nop
00930034 F8 clc
00930035 F9 stc
00930036 F9 stc
00930037 04 93 add al,93
00930039 0AC0 or al,al
0093003B 90 nop
0093003C 0AC0 or al,al
0093003E F8 clc
0093003F FEC8 dec al
00930041 2C 51 sub al,51
00930046 FEC8 dec al
00930048 34 21 xor al,21
00930050 FEC8 dec al
00930052 AA stos byte ptr es:[edi]
00930053 49 dec ecx
00930054 ^ 75 D2 jnz short 00930028(留心)
0093005F 61 popad
00930060 9D popfd
00930061 C3 retn
9C608B4424 248B088D78 04897C24 2481E9 CDEF041FFC8A07C0C0 9590F8F9F904 930AC0 900AC0F8 FEC82C 51FEC8 34 21 FEC8 AA 4975 D2619DC3
找到空白处修复,变成
00401950 E8 18620000 call extdfx16.00407B6D
00401955 90 nop
00407B6D 9C pushfd
00407B6E 60 pushad
00407B6F 8B4424 24 mov eax,dword ptr ss:[esp+24]
00407B73 8B08 mov ecx,dword ptr ds:[eax]
00407B75 8D78 04 lea edi,dword ptr ds:[eax+4]
00407B78 897C24 24 mov dword ptr ss:[esp+24],edi
00407B7C 81E9 CDEF041F sub ecx,1F04EFCD
00407B82 FC cld
00407B83 8A07 mov al,byte ptr ds:[edi]
00407B85 C0C0 95 rol al,95
00407B88 90 nop
00407B89 F8 clc
00407B8A F9 stc
00407B8B F9 stc
00407B8C 04 93 add al,93
00407B8E 0AC0 or al,al
00407B90 90 nop
00407B91 0AC0 or al,al
00407B93 F8 clc
00407B94 FEC8 dec al
00407B96 2C 51 sub al,51
00407B98 FEC8 dec al
00407B9A 34 21 xor al,21
00407B9C FEC8 dec al
00407B9E AA stos byte ptr es:[edi]
00407B9F 49 dec ecx
00407BA0 ^ 75 E1 (指向8A07一句) jnz short dumped_e.00407B83
00407BA2 61 popad
00407BA3 9D popfd
00407BA4 C3 retn
9C 60 8B 44 24 24 8B 08 8D 78 04 89 7C 24 24 81 E9 CD EF 04 1F FC 8A 07 C0 C0 95 90 F8 F9 F9 04
93 0A C0 90 0A C0 F8 FE C8 2C 51 FE C8 34 21 FE C8 AA 49 75 E1 61 9D C3
00930003 9C pushfd
00930007 60 pushad
00930008 8B4424 24 mov eax,dword ptr ss:[esp+24]
0093000C 8B08 mov ecx,dword ptr ds:[eax]
0093000E 8D78 04 lea edi,dword ptr ds:[eax+4]
00930011 897C24 24 mov dword ptr ss:[esp+24],edi
00930015 81E9 CDEF041F sub ecx,1F04EFCD
0093001B FC cld
00930028 8A07 mov al,byte ptr ds:[edi]
00930030 C0C0 95 rol al,95
00930033 90 nop
00930034 F8 clc
00930035 F9 stc
00930036 F9 stc
00930037 04 93 add al,93
00930039 0AC0 or al,al
0093003B 90 nop
0093003C 0AC0 or al,al
0093003E F8 clc
0093003F FEC8 dec al
00930041 2C 51 sub al,51
00930046 FEC8 dec al
00930048 34 21 xor al,21
00930050 FEC8 dec al
00930052 AA stos byte ptr es:[edi]
00930053 49 dec ecx
00930054 ^ 75 D2 jnz short 00930028(留心)
0093005F 61 popad
00930060 9D popfd
00930061 C3 retn
9C608B4424 248B088D78 04897C24 2481E9 CDEF041FFC8A07C0C0 9590F8F9F904 930AC0 900AC0F8 FEC82C 51FEC8 34 21 FEC8 AA 4975 D2619DC3
找到空白处修复,变成
00401950 E8 18620000 call extdfx16.00407B6D
00401955 90 nop
00407B6D 9C pushfd
00407B6E 60 pushad
00407B6F 8B4424 24 mov eax,dword ptr ss:[esp+24]
00407B73 8B08 mov ecx,dword ptr ds:[eax]
00407B75 8D78 04 lea edi,dword ptr ds:[eax+4]
00407B78 897C24 24 mov dword ptr ss:[esp+24],edi
00407B7C 81E9 CDEF041F sub ecx,1F04EFCD
00407B82 FC cld
00407B83 8A07 mov al,byte ptr ds:[edi]
00407B85 C0C0 95 rol al,95
00407B88 90 nop
00407B89 F8 clc
00407B8A F9 stc
00407B8B F9 stc
00407B8C 04 93 add al,93
00407B8E 0AC0 or al,al
00407B90 90 nop
00407B91 0AC0 or al,al
00407B93 F8 clc
00407B94 FEC8 dec al
00407B96 2C 51 sub al,51
00407B98 FEC8 dec al
00407B9A 34 21 xor al,21
00407B9C FEC8 dec al
00407B9E AA stos byte ptr es:[edi]
00407B9F 49 dec ecx
00407BA0 ^ 75 E1 (指向8A07一句) jnz short dumped_e.00407B83
00407BA2 61 popad
00407BA3 9D popfd
00407BA4 C3 retn
9C 60 8B 44 24 24 8B 08 8D 78 04 89 7C 24 24 81 E9 CD EF 04 1F FC 8A 07 C0 C0 95 90 F8 F9 F9 04
93 0A C0 90 0A C0 F8 FE C8 2C 51 FE C8 34 21 FE C8 AA 49 75 E1 61 9D C3
三、处理Code Redirection(没有偷代码,有定向到PE头):多次运行PESpin 1.x - Code Fixer.txt修复脚本,不能再修复为止
第一种重定向(CALL-JMP):特征码#E8??????FF#
00401DA8 E8 8AE4FFFF call extdfx16.00400237
第二种重定向(JMP-PUSH):特征码#E9??????FF#
00401D2A - E9 ADE4FFFF jmp extdfx16.004001DC
第三种重定向(JMP- CMP):特征码#E9??????FF9090#
00401D35 - E9 ADE4FFFF jmp extdfx16.004001E7
00401D3A 90 nop
00401D3B 90 nop
第一种重定向(CALL-JMP):特征码#E8??????FF#
00401DA8 E8 8AE4FFFF call extdfx16.00400237
第二种重定向(JMP-PUSH):特征码#E9??????FF#
00401D2A - E9 ADE4FFFF jmp extdfx16.004001DC
第三种重定向(JMP- CMP):特征码#E9??????FF9090#
00401D35 - E9 ADE4FFFF jmp extdfx16.004001E7
00401D3A 90 nop
00401D3B 90 nop
四、UIF修复指针:API大多被定向到壳地址,我们想把它放在0040A000段(看M镜像)
此处省去口口口口......10000多字,请看ximo老师教程
此处省去口口口口......10000多字,请看ximo老师教程
五、Dump:LordPE(修正大小)来Dump为dumped.exe,填入OEP:32D6,ImportREC自动方式获取API,转存为dumped_.exe后发现不能运行。
六、BUG修复:
注:以下老OD是载入目标extdfx169.exe,并且HE 004032D6直接运行到OEP
先前载入目标extdfx169.exe走到OEP的OD不要关(也不要运行,需要时只是跟随查找),以便对比。
1、另开OD载入dumped_.exe,发现堆栈不对(不知道是不是防Dump的地方没有处理好?)
老OD栈顶:0012FFC0 00416B0B extdfx16.00416B0B(返回值)
跟随发现实际返回到这里00401A6C 6A 60 push 60
新OD栈顶:0012FFC4 7C817077 返回到 kernel32.7C817077
所以只需找空地PUSH 00401A6C再返回到旧OEP就好了,例如:
00407B63 68 6C1A4000 push dumped_.00401A6C
00407B68 ^ E9 69B7FFFF jmp dumped_.<模块入口点>
保存修改到文件dumped_1.exe,用LordPE改变入口OEP=00007B63并验证重建一下
,可以运行了
。
老OD栈顶:0012FFC0 00416B0B extdfx16.00416B0B(返回值)
跟随发现实际返回到这里00401A6C 6A 60 push 60
新OD栈顶:0012FFC4 7C817077 返回到 kernel32.7C817077
所以只需找空地PUSH 00401A6C再返回到旧OEP就好了,例如:
00407B63 68 6C1A4000 push dumped_.00401A6C
00407B68 ^ E9 69B7FFFF jmp dumped_.<模块入口点>
保存修改到文件dumped_1.exe,用LordPE改变入口OEP=00007B63并验证重建一下
,可以运行了
。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-2-19 11:19
被ejamse编辑
,原因: 改正错误