-
-
[原创]一点脱壳的笔记
-
发表于: 2012-5-3 01:21 16794
-
笔记.rar
练过手的,常见壳脱壳步骤都做了记录(极大部分百度和一些视频教程),其中以壳脱壳的一些理论有点意思,逆向的学习要停一段时间了,最近人工智能什么的开始期末复习了,忙一下课内。这份东西待续吧。还是有很多壳的,每种壳又N多种anti,幸运的是大部分都有教程,通过模拟重现,再总结为什么这样做,比如为什么ESP定理有效,为什么最后一次异常法可以发挥作用,stolen code怎么跟踪,为什么两次内存断点可以发挥作用,这些东西里面都有提及,不光是模拟前人。估计不是对每个人有用,觉得有用的就扫一眼吧。
对应的练手的程序。
115 下载:http://115.com/file/c2ev3mxh#脱壳笔记.rar
【脱壳一般流程】
查壳(PEID、FI、PE-SCAN)--->寻找OEP(OD)--->脱壳/Dump(LordPE、PeDumper、OD自带的脱壳插件、PETools)--->修复(Import REConstructor)
【工具介绍】
1、查壳
PEID--功能强大的侦壳工具,自带脱壳插件(但是,效果不怎么样)
工作原理:核心是userdb.txt(大家看看就完全明白了)[通过壳的入口特征码进行辨认]
使用方法:可以拖放、也可以把PEID添加到右键菜单里面去
FI--功能强大的侦壳工具,DOS界面。
使用方法:可以拖放、可以使用DOS命令行
2、寻找OEP
ollydbg的四个区域
左上角是cpu窗口,分别是地址,机器码,汇编代码,注释;注释添加方便,而且还能即时显示函数的调用结果,返回值.
右上角是寄存器窗口,但不仅仅反映寄存器的状况,还有好多东东;双击即可改变Eflag的值,对于寄存器,指令执行后发生改变的寄存器会用红色突出显示.
cpu窗口下面还有一个小窗口,显示当前操作改变的寄存器状态.
左下角是内存窗口.可以ascii或者unicode两种方式显示内存信息.
右下角的是当前堆栈情况,还有注释啊.
几个经常使用的快捷键
F2:在需要的地方下断点(INT3型断点)
F3:选择打开程序
F4:运行到所选择的那一行
F7:单步进入
F8:单步跟踪
F9:执行程序(运行程序)
其中要特别讲一下3个F9的区别和作用:
根据Ollydbg.hlp的中文翻译
Shift+F9 - 与F9相同,但是如果被调试程序发生异常而中止,调试器会首先尝试执行被调试程序指定的异常处理(请参考忽略Kernel32中的内存非法访问)。
Ctrl+F9 - 执行直到返回,跟踪程序直到遇到返回,在此期间不进入子函数也不更新CPU数据。因为程序是一条一条命令执行的,所以速度可能会慢一些。按Esc键,可以停止跟踪。
Alt+F9 - 执行直到返回到用户代码段,跟踪程序直到指令所属于的模块不在系统目录中,在此期间不进入子函数也不更新CPU数据。因为程序是一条一条执行的,所以速度可能会慢一些。按Esc键,可以停止跟踪。
看这些中文介绍大家可能还不是很明白,用我们通俗的语句来说就是:
Ctrl+F9 运行至retn (一般到了retn之后接上F7返回)
Alt+F9 运行至上层调用的下句
Shift+F9 忽略异常运行
文件:
1.其中包括该菜单的下部有上次打开的纪录,该纪录保存有上次未清除的断点.
2.附加.对付那些Anti-Debug程序.先运行程序,再运行od,文件-->附加.
查看:
1.执行模块(Alt+E),查看程序使用的动态链接库
2.查看断点.Alt+B
调试:
1.运行(F9)加载程序后,运行!
2.暂停(F12)
3.单步进入(F7)遇见CALL进入!进入该子程序.
4.单步跳过(F8)遇见CALL不进去!
5.执行到返回(ALT+F9)就是执行到该子程的返回语句
查看-->文件
二进制文件编辑功能.查看-->文件,打开的文件是二进制显示.选中要改变的机器指令,空格,修改,右击-->保存.
具体的用途在后面的几壳脱壳课程当中将会用到,大家现在理解就行。在后面的操作中学会使用!
其他的一些具体的大家还是要看看OD的中文帮助的
3、Dump
OD自带的脱壳插件--到达OEP之后右键。。。
LordPE、PeDumper--选择所调试的进程--右键--完整脱壳
4、修复
Import REConstructor 1.6
【壳的介绍】
壳出于程序作者想对程序资源压缩、注册保护的目的,把壳分为压缩壳和加密壳两种
UPX ASPCAK TELOCK PELITE NSPACK ...
ARMADILLO ASPROTECT ACPROTECT EPE SVKP ...
顾名思义,压缩壳只是为了减小程序体积对资源进行压缩,加密壳是程序输入表等等进行加密保护。当然加密壳的保护能力要强得多!
【常见的脱壳方法】
预备知识
1.PUSHAD (压栈) 代表程序的入口点,
2.POPAD (出栈) 代表程序的出口点,与PUSHAD想对应,一般找到这个OEP就在附近
3.OEP:程序的入口点,软件加壳就是隐藏了OEP(或者用了假的OEP/FOEP),只要我们找到程序真正的OEP,就可以立刻脱壳。
方法一:单步跟踪法
1.用OD载入,点“不分析代码!”
2.单步向下跟踪F8,实现向下的跳。也就是说向上的跳不让其实现!(通过F4)
3.遇到程序往回跳的(包括循环),我们在下一句代码处按F4(或者右健单击代码,选择断点——>运行到所选)
4.绿色线条表示跳转没实现,不用理会,红色线条表示跳转已经实现!
5.如果刚载入程序,在附近就有一个CALL的,我们就F7跟进去,不然程序很容易跑飞,这样很快就能到程序的OEP
6.在跟踪的时候,如果运行到某个CALL程序就运行的,就在这个CALL中F7进入
7.一般有很大的跳转(大跨段),比如 jmp XXXXXX 或者 JE XXXXXX 或者有RETN的一般很快就会到程序的OEP。
Btw:在有些壳无法向下跟踪的时候,我们可以在附近找到没有实现的大跳转,右键-->“跟随”,然后F2下断,Shift+F9运行停在“跟随”的位置,再取消断点,继续F8单步跟踪。一般情况下可以轻松到达OEP!
方法二:ESP定律法
ESP定理脱壳(ESP在OD的寄存器中,我们只要在命令行下ESP的硬件访问断点,就会一下来到程序的OEP了!)
1.开始就点F8,注意观察OD右上角的寄存器中ESP有没突现(变成红色)。(这只是一般情况下,更确切的说我们选择的ESP值是关键句之后的第一个ESP值)
2.在命令行下:dd XXXXXXXX(指在当前代码中的ESP地址,或者是hr XXXXXXXX),按回车!
3.选中下断的地址,断点--->硬件访--->WORD断点。
4.按一下F9运行程序,直接来到了跳转处,按下F8,到达程序OEP。
方法三:内存镜像法
1:用OD打开软件!
2:点击选项——调试选项——异常,把里面的忽略全部√上!CTRL+F2重载下程序!
3:按ALT+M,打开内存镜象,找到程序的第一个.rsrc.按F2下断点,然后按SHIFT+F9运行到断点,接着再按ALT+M,打开内存镜象,找到程序的第一个.rsrc.上面的.CODE(也就是00401000处),按F2下断点!然后按SHIFT+F9(或者是在没异常情况下按F9),直接到达程序OEP!
注:.rsrc是资源,一般壳都对资源进行操作,所以上面的
方法四:一步到达OEP
1.开始按Ctrl+F,输入:popad(只适合少数壳,包括UPX,ASPACK壳),然后按下F2,F9运行到此处
2.来到大跳转处,点下F8,到达OEP!
这个定理是最有效的
方法五:最后一次异常法
1:用OD打开软件
2:点击选项——调试选项——异常,把里面的√全部去掉!CTRL+F2重载下程序
3:一开始程序就是一个跳转,在这里我们按SHIFT+F9,直到程序运行,记下从开始按SHIFT+F9到程序运行的次数m!
4:CTRL+F2重载程序,按SHIFT+F9(这次按的次数为程序运行的次数m-1次)
5:在OD的右下角我们看见有一个"SE 句柄",这时我们按CTRL+G,输入SE 句柄前的地址!
6:按F2下断点!然后按SHIFT+F9来到断点处!
7:去掉断点,按F8慢慢向下走!
8:到达程序的OEP!
方法六:模拟跟踪法
1:先试运行,跟踪一下程序,看有没有SEH暗桩之类
2:ALT+M打开内存镜像,找到(包含=SFX,imports,relocations)
内存镜像,项目 30
地址=0054B000
大小=00002000 (8192.)
Owner=check 00400000
区段=.aspack
包含=SFX,imports,relocations
类型=Imag 01001002
访问=R
初始访问=RWE
3:地址为0054B000,如是我们在命令行输入tc eip<0054B000,回车,正在跟踪ing。。
Btw:大家在使用这个方法的时候,要理解他是要在怎么样的情况下才可以使用
方法七:“SFX”法
1:设置OD,忽略所有异常,也就是说异常选项卡里面都打上勾
2:切换到SFX选项卡,选择“字节模式跟踪实际入口(速度非常慢)”,确定。
3:重载程序(如果跳出是否“压缩代码?”选择“否”,OD直接到达OEP)
Btw:这种方法不要滥用得好,锻炼能力为妙。
【UXP练手】【附件 upx.exe】
---------------------------------------------------------------------------------
黑鹰红客基地动画教程
黑鹰红客基地www.3800cc.com
专业的红客安全技术培训基地
多抽出一分钟时间学习.让你的生命更加精彩.
注:10元的动画免费对外公布.20.50.100.200元的动画只提供给本站的vip会员做为辅助教材.
---------------------------------------------------------------------------------
手脱UPX的四种方法
首先,查壳,使用PEID是UPX 0.89.6 - 1.02 / 1.05 - 1.24 -> Markus & Laszlo,使用FI为UPX v1.08
接下来用OD载入,提示为“压缩代码是否继续分析”,我们选择否
我在这里介绍几种方法,请看我的操作。
方法1:单步跟踪(最常见的方法)
0040E8C0 N> 60 pushad //停在这里了,我们F8单步
0040E8C1 BE 15B04000 mov esi,NOTEPAD.0040B015
0040E8C6 8DBE EB5FFFFF lea edi,dword ptr ds:[esi+FFFF>
0040E8CC 57 push edi
0040E8CD 83CD FF or ebp,FFFFFFFF
0040E8D0 EB 10 jmp short NOTEPAD.0040E8E2 //跳
》》》》
0040E8E2 8B1E mov ebx,dword ptr ds:[esi] //跳到这里
0040E8E4 83EE FC sub esi,-4
0040E8E7 11DB adc ebx,ebx
0040E8E9 ^ 72 ED jb short NOTEPAD.0040E8D8 //这里要往回跳了
0040E8EB B8 01000000 mov eax,1 //F4,然后继续F8
0040E8F0 01DB add ebx,ebx
0040E8F2 75 07 jnz short NOTEPAD.0040E8FB //跳
》》》》
0040E8FB 11C0 adc eax,eax //来到这里,F8继续
0040E8FD 01DB add ebx,ebx
0040E8FD 01DB add ebx,ebx
0040E8FF ^ 73 EF jnb short NOTEPAD.0040E8F0
0040E901 75 09 jnz short NOTEPAD.0040E90C //跳
》》》》
0040E90C 31C9 xor ecx,ecx //跳到这里,继续F8
0040E90E 83E8 03 sub eax,3
0040E90E 83E8 03 sub eax,3
0040E911 72 0D jb short NOTEPAD.0040E920 //跳
》》》》
0040E920 01DB add ebx,ebx //跳到这里,继续F8
0040E922 75 07 jnz short NOTEPAD.0040E92B //跳
》》》
0040E92B 11C9 adc ecx,ecx //跳到了这里,继续F8
0040E92D 01DB add ebx,ebx
0040E92F 75 07 jnz short NOTEPAD.0040E938 //跳
》》》
0040E938 11C9 adc ecx,ecx //跳到这里,继续F8
0040E93A 75 20 jnz short NOTEPAD.0040E95C //跳
》》》》
0040E95C 81FD 00F3FFFF cmp ebp,-0D00 //来到这,继续F8
0040E962 83D1 01 adc ecx,1
0040E965 8D142F lea edx,dword ptr ds:[edi+ebp]
0040E968 83FD FC cmp ebp,-4
0040E96B 76 0F jbe short NOTEPAD.0040E97C
0040E96D 8A02 mov al,byte ptr ds:[edx]
0040E96F 42 inc edx
0040E970 8807 mov byte ptr ds:[edi],al
0040E972 47 inc edi
0040E973 49 dec ecx
0040E974 ^ 75 F7 jnz short NOTEPAD.0040E96D //要往回跳了
0040E976 ^ E9 63FFFFFF jmp NOTEPAD.0040E8DE
0040E97B 90 nop
0040E97C 8B02 mov eax,dword ptr ds:[edx]// F4,继续F8
0040E97E 83C2 04 add edx,4
0040E981 8907 mov dword ptr ds:[edi],eax
0040E983 83C7 04 add edi,4
0040E986 83E9 04 sub ecx,4
0040E989 ^ 77 F1 ja short NOTEPAD.0040E97C
0040E98B 01CF add edi,ecx
0040E98D ^ E9 4CFFFFFF jmp NOTEPAD.0040E8DE //要往回跳了。
0040E992 5E pop esi //这里F4,继续F8
0040E993 89F7 mov edi,esi
0040E995 B9 DD000000 mov ecx,0DD
0040E99A 8A07 mov al,byte ptr ds:[edi]
0040E99C 47 inc edi
0040E99D 2C E8 sub al,0E8
0040E99F 3C 01 cmp al,1
0040E9A1 ^ 77 F7 ja short NOTEPAD.0040E99A //要往回跳了
0040E9A3 803F 00 cmp byte ptr ds:[edi],0 //这里F4,继续F8
0040E9A6 ^ 75 F2 jnz short NOTEPAD.0040E99A //要往回跳了
0040E9A8 8B07 mov eax,dword ptr ds:[edi] // F4,继续F8
0040E9AA 8A5F 04 mov bl,byte ptr ds:[edi+4]
0040E9AD 66:C1E8 08 shr ax,8
0040E9B1 C1C0 10 rol eax,10
0040E9B4 86C4 xchg ah,al
0040E9B6 29F8 sub eax,edi
0040E9B8 80EB E8 sub bl,0E8
0040E9BB 01F0 add eax,esi
0040E9BD 8907 mov dword ptr ds:[edi],eax
0040E9BF 83C7 05 add edi,5
0040E9C2 89D8 mov eax,ebx
0040E9C4 ^ E2 D9 loopd short NOTEPAD.0040E99F //要往回跳了
0040E9C6 8DBE 00C00000 lea edi,dword ptr ds:[esi+C000> //F4继续F8
0040E9CC 8B07 mov eax,dword ptr ds:[edi]
0040E9CE 09C0 or eax,eax
0040E9D0 74 3C je short NOTEPAD.0040EA0E
0040E9D2 8B5F 04 mov ebx,dword ptr ds:[edi+4]
0040E9D5 8D8430 14EC00>lea eax,dword ptr ds:[eax+esi+>
0040E9DC 01F3 add ebx,esi
0040E9DE 50 push eax
0040E9DF 83C7 08 add edi,8
0040E9E2 FF96 A0EC0000 call dword ptr ds:[esi+ECA0]
0040E9E8 95 xchg eax,ebp
0040E9E9 8A07 mov al,byte ptr ds:[edi]
0040E9EB 47 inc edi
0040E9EC 08C0 or al,al
0040E9EE ^ 74 DC je short NOTEPAD.0040E9CC
0040E9F0 89F9 mov ecx,edi
0040E9F2 57 push edi
0040E9F3 48 dec eax
0040E9F4 F2:AE repne scas byte ptr es:[edi]
0040E9F6 55 push ebp
0040E9F7 FF96 A4EC0000 call dword ptr ds:[esi+ECA4]
0040E9FD 09C0 or eax,eax
0040E9FF 74 07 je short NOTEPAD.0040EA08
0040EA01 8903 mov dword ptr ds:[ebx],eax
0040EA03 83C3 04 add ebx,4
0040EA06 ^ EB E1 jmp short NOTEPAD.0040E9E9 //要往回跳了
0040EA08 FF96 A8EC0000 call dword ptr ds:[esi+ECA8]
0040EA0E 61 popad //这里F4,继续F8
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC //在这里直接跳到了OEP
》》》》
004010CC 55 push ebp //来到这里,在此dump
004010CD 8BEC mov ebp,esp
004010CF 83EC 44 sub esp,44
其他操作请看动画
方法2:ESP定律手动脱壳
0040E8C0 N> 60 pushad //停在这里了,我们F8单步
0040E8C1 BE 15B04000 mov esi,NOTEPAD.0040B015 //ESP突现,0012FFA4
dd 0012FFA4回车, 断点--硬件访问--WORD,F9运行,直接来到这里
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC //来到这单步就到了OEP
不详述,和方法一一样了
方法3:内存镜像法
(由于经过了方法2和方法3大家都熟悉了代码,我在这里就不写了)
ALT+M打开内存
找到.rsrc,F2下断,F9运行
。。。。。。
ALT+M打开内存
找到UPX0,F2下断,F9运行
0040EA01 8903 mov dword ptr ds:[ebx],eax//来到这,F8继续
0040EA03 83C3 04 add ebx,4
0040EA06 ^ EB E1 jmp short NOTEPAD.0040E9E9
0040EA08 FF96 A8EC0000 call dword ptr ds:[esi+ECA8]
0040EA0E 61 popad
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC
其他的就不说了~请看动画。
方法4:捷径
直接CTRL+F,输入popad
0040EA0E 61 popad//F2下断,F9运行,F2取消断点,单步F8
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC
---------------------------------------------------------------------------------
【aspack脱壳练手】
【AsPack-KillBox.exe】
【AsPack-登陆器.exe】
“KillBox”用PEID查得是ASPack 2.12 -> Alexey Solodovnikov
1、单步跟踪法
2、ESP定律法
00424001 K> 60 pushad //入口,看到关键提示大家就应该惊醒了,单步F8
00424002 E8 03000000 call KillBox.0042400A //到这里,注意寄存器提示ESP=0012FFA4
00424007 - E9 EB045D45 jmp 459F44F7
0042400C 55 push ebp
0042400D C3 retn
命令行下断hr 0012FFA4,F9运行!
3、内存镜像法
首先Alt+M打开内存镜像
找到.rsrc区段
内存映射,项目 29
地址=004D3000
大小=00241000 (2363392.)
宿主=登陆器 00400000
区段=.rsrc //F2下断,Shift+F9运行!
包含=resources
类型=Imag 01001002
访问=R
初始访问=RWE
继续
内存映射,项目 22
地址=00401000
大小=000BB000 (765952.)
宿主=登陆器 00400000
区段=CODE //F2下断,Shift+F9运行!直接到达OEP!
包含=code
类型=Imag 01001002
访问=R
初始访问=RWE
********************************************************************************************
"登陆器"其实是一个ASPack的变形壳
今天我们使用2种方法快速搞定它!
一、ESP定律法
二、内存断点法
******************************************************************************************************
一、ESP定律法
OD载入程序
00717082 登陆> 60 pushad //入口,看到关键提示大家就应该惊醒了,单步F8
00717083 E8 00000000 call 登陆器.00717088 //到这里,注意寄存器提示ESP=0012FFA4
00717088 5D pop ebp
00717089 81ED B6A4450>sub ebp,登陆器.0045A4B6
0071708F 8DBD B0A4450>lea edi,dword ptr ss:[ebp+45A4B0]
00717095 81EF 8200000>sub edi,82
命令行下断hr 0012FFA4,F9运行!
00717374 - FFE0 jmp eax ; 登陆器.00714001 //到这里,单步F8
00717376 42 inc edx
00717377 4B dec ebx
00717378 2E:44 inc esp
0071737A 41 inc ecx
00714001 60 pushad //来到这里,仍然是关键提示,单步F8
00714002 E8 03000000 call 登陆器.0071400A //到这里,ESP=0012FFA4(和上面的一样),由于上一个硬件断点没删除所以到这里我们直接F9就可以了!
00714007 - E9 EB045D45 jmp 45CE44F7
0071400C 55 push ebp
0071400D C3 retn
007143B0 /75 08 jnz short 登陆器.007143BA //到这里!删除断点,F8
007143B2 |B8 01000000 mov eax,1
007143B7 |C2 0C00 retn 0C
007143BA \68 D8BD4B00 push 登陆器.004BBDD8
007143BF C3 retn //返回到 004BBDD8 (登陆器.004BBDD8),程序的OEP!
004BBDD8 55 push ebp //OEP,看入口代码特征就知道程序是Delphi写的
004BBDD9 8BEC mov ebp,esp
004BBDDB 83C4 F0 add esp,-10
004BBDDE B8 98B94B00 mov eax,登陆器.004BB998
004BBDE3 E8 BCA5F4FF call 登陆器.004063A4
004BBDE8 A1 7CE84B00 mov eax,dword ptr ds:[4BE87C]
004BBDED 8B00 mov eax,dword ptr ds:[eax]
004BBDEF E8 1073FAFF call 登陆器.00463104
在此LordPE完全Dump!请出Import来修复下!OEP处填BBDD8--自动搜索IAT--获取输入表(全部有效)--FixDump!
测试正常运行,用PEID查看是Borland Delphi 6.0 - 7.0写的
好了,ESP定律法就到这里,下面介绍的是内存断点法
******************************************************************************************************
二、内存断点法
重新载入下吧,来实行我们的内存断点法
首先Alt+M打开内存镜像
找到.rsrc区段
内存映射,项目 29
地址=004D3000
大小=00241000 (2363392.)
宿主=登陆器 00400000
区段=.rsrc //F2下断,Shift+F9运行!
包含=resources
类型=Imag 01001002
访问=R
初始访问=RWE
77F764F3 66:8B50 0C mov dx,word ptr ds:[eax+C] //来到这里,我们不用管它
77F764F7 8995 6CFFFFF>mov dword ptr ss:[ebp-94],edx
77F764FD 8D70 10 lea esi,dword ptr ds:[eax+10]
77F76500 89B5 68FFFFF>mov dword ptr ss:[ebp-98],esi
77F76506 66:F747 02 F>test word ptr ds:[edi+2],0FFFF
再次Alt+M打开内存镜像
找到.code区段或者是.text区段(因为编写语言不一样所以区段名称的一样的,一般是00401000段)
内存映射,项目 22
地址=00401000
大小=000BB000 (765952.)
宿主=登陆器 00400000
区段=CODE //F2下断,Shift+F9运行!直接到达OEP!
包含=code
类型=Imag 01001002
访问=R
初始访问=RWE
004BBDD8 55 push ebp //OEP,看入口代码特征就知道程序是Delphi写的
004BBDD9 8BEC mov ebp,esp
004BBDDB 83C4 F0 add esp,-10
004BBDDE B8 98B94B00 mov eax,登陆器.004BB998
004BBDE3 E8 BCA5F4FF call 登陆器.004063A4
004BBDE8 A1 7CE84B00 mov eax,dword ptr ds:[4BE87C]
在此LordPE完全Dump!请出Import来修复下!OEP处填BBDD8--自动搜索IAT--获取输入表(全部有效)--FixDump!
测试正常运行,用PEID查看是Borland Delphi 6.0 - 7.0写的
【fsg 脱壳练手】
【fsg 1.33.exe】
【FSG 1.33变形壳.exe】
【FSG 2.0】
【fsg 1.33.exe】
方法一:单步法(忽略所有异常)
方法二:ESP定律(忽略所有异常)
这里没有明显的pushad指令,但是还是满足ESP定理的,单步如下
004103ED 56 push esi
004103EE 96 xchg eax,esi ; fsg_1_33.004001B0
004103EF B2 80 mov dl,0x80
004103F1 A4 movs byte ptr es:[edi],byte ptr ds:[esi]
在xchg eax,esi 处,发现esp寄存器发生变化,这是通过代码变形,使得不用直接使用pushad。
对 00112FFC0对应的数据下硬件断点,运行到达这里
0041045A AD lods dword ptr ds:[esi]
0041045B 48 dec eax
0041045C 74 0A je Xfsg_1_33.00410468
0041045E 79 02 jns Xfsg_1_33.00410462
00410460 AD lods dword ptr ds:[esi]
这里撤销硬件断点,单步,很快就可以到OEP了
00410480 /EB 09 jmp Xfsg_1_33.0041048B
00410482 |FE0E dec byte ptr ds:[esi]
00410484 -|0F84 420CFFFF je fsg_1_33.004010CC
0041048A |56 push esi
0041048B \55 push ebp
这里的判断ds:[esi]里面的值,如果等于0,就跳装到4010CC,这个就是OEP了,这是这个壳的一个特点,熟悉一下就行。
(dump的时候断点要取出,不然断点出dump下来的是int 3)
方法三:模拟跟踪法(不忽略内存异常)[首先忽略所有异常,F9试运行一下,遇到异常,好我们现在试下不忽略内存异常,(这是一个自己尝试的过程目的就是是要找到好多调试设置!),再试运行,OK,程序运行了。。要的就是他,模拟跟踪法是需要在没有异常的情况下才能够完全运用的]
ALT+M,打开内存镜像,
内存镜像,项目 15
地址=0040C000
大小=00005000 (20480.)
Owner=fsg_1_33 00400000
区段=
包含=SFX,imports,resources
类型=Imag 01001002
访问=R
初始访问=RWE
下命令行tc eip<0040c000,enter。正在跟踪之中。。。。有时候需要点时间等~
【FSG 1.33变形壳.exe】
单步几步,ESP=0012FFC0的时候,跟随到数据窗口中,下硬件访问断点,在来到的地方单步到这里
这段循环跟踪一下,就知道是处理IAT表的00430801 /EB 09 jmp short 0043080C这句一直得不到运行,直接下断点让其运行,在单步几步,就运行到这里了
00402666 55 push ebp ; COMCTL32.#241
00402667 8BEC mov ebp, esp
00402669 6A FF push -1
0040266B 68 00674100 push 00416700
00402670 68 FC504000 push 004050FC
00402675 64:A1 00000000 mov eax, dword ptr fs:[0]
0040267B 50 push eax
0040267C 64:8925 0000000>mov dword ptr fs:[0], esp
00402683 83EC 58 sub esp, 58
00402686 53 push ebx
00402687 56 push esi
00402688 57 push edi
00402689 8965 E8 mov dword ptr [ebp-18], esp
0040268C FF15 14524100 call dword ptr [415214] ; kernel32.GetVersion
很明显的VC入口特征。这里就是OEP了
修复的时候发现有个指针是无效的,我们就剪切掉吧。
这时候还是不可以运行。重新用od导入修复后的文件,发现有一个int 异常,直接nop掉
0040127E 90 nop
0040127F 90 nop
00401280 |> 8D4D E4 lea ecx, dword ptr [ebp-1C]
然后就可以运行了。
【FSG 2.0.exe】
直接用ESP定理,在入口出单步几步,直到
0040015D A4 movs byte ptr es:[edi], byte ptr [esi]
对esp跟踪到数据里面,对对应的数据设置内存断点。
004001C2 AD lods dword ptr [esi]
004001C3 97 xchg eax, edi
004001C4 AD lods dword ptr [esi]
到达这里之后,先删除断点 ,跟踪几步就到了。
在这个图里面,可以看到jmp dword ptr[ebx+C]一直没有被执行,对其F2,然后F9
可以看到ds:[004133A4]=00401000 (fsg_2_0.00401000),401000刚好是代码段附近的,这里就是OEP了,跟随进去。
00401000 2BDB sub ebx, ebx ; fsg_2_0.00413398
00401002 B8 4CA04000 mov eax, 0040A04C
00401007 C700 08000000 mov dword ptr [eax], 8
0040100D C740 04 FF00000>mov dword ptr [eax+4], 0FF
这时候用Import REC是无效的,fsg2.0对输入表加密了(或者有hook)
00401015 E8 DC620000 call 004072F6 ; jmp 到 COMCTL32.InitCommonControlsEx
看这一句,跟随进去,马上看到HOOK表了
0040723C - FF25 54904000 jmp dword ptr [409054] ; kernel32.CreateFileMappingA
00407242 - FF25 50904000 jmp dword ptr [409050] ; kernel32.CreateThread
……………………………..
004072F0 - FF25 08904000 jmp dword ptr [409008] ; GDI32.GetObjectA
004072F6 - FF25 00904000 jmp dword ptr [409000] ; COMCTL32.InitCommonControlsEx
跟随进入数据窗口,执行命令d 409060,进入数据窗口,上下翻动,可以看到转存的IAT表
00409000 77184088 園w COMCTL32.InitCommonControlsEx
…………………………………………………………………………
0040908C 77D24A4E NJ襴 USER32.EndDialog
00409090 7FFFFFFF
00409094 7632309F ?2v comdlg32.GetOpenFileNameA
00409098 7FFFFFFF
计算一下便宜,填进去就可以了,IAT RVA=9000,size=98
把无效指针剪切出来就行了
【PECompact 】
【PECompact 1.84.exe】一个ESP定理搞定
【PECompact 2.55.EXE】
这个壳一开始就给你弄了个SHE异常
FS寄存器指向当前活动线程的TEB结构(线程结构)偏移 说明000 指向SEH链指针004 线程堆栈顶部008 线程堆栈底部00C SubSystemTib010 FiberData014 ArbitraryUserPointer018 FS段寄存器在内存中的镜像地址020 进程PID024 线程ID02C 指向线程局部存储指针030 PEB结构地址(进程结构)034 上个错误号
参考< http://bbs.pediy.com/archive/index.php?t-100224.html>
所以这里ESP不好用了。
这里用了前人一个套路(最不喜欢套路了,没自己弄明白)
设置Ollydbg忽略所有的异常选项。
od载入
01001000 N> B8 90BA0101 mov eax,NOTEPAD.0101BA90
01001005 50 push eax ; NOTEPAD.0101BA90
01001006 64:FF35 0000000>push dword ptr fs:[0]
0100100D 64:8925 0000000>mov dword ptr fs:[0],esp
01001014 33C0 xor eax,eax
01001016 8908 mov dword ptr ds:[eax],ecx
01001018 50 push eax
下断点:BP VirtualFree。中断后,取消断点,Alt+F9。
002F00C0 58 pop eax //返回到这
002F00C1 EB 03 jmp short 002F00C6
002F00C3 33C0 xor eax,eax
002F00C5 48 dec eax
002F00C6 5D pop ebp
002F00C7 5B pop ebx
然后,ctrl+F ,查找 push 8000(特征码)。
002F093E 03C7 add eax,edi
002F0940 68 00800000 push 8000 //这里
002F0945 6A 00 push 0
002F0947 FFB5 951C0010 push dword ptr ss:[ebp+10001C95]
002F094D FF10 call dword ptr ds:[eax]
002F094F 8B46 0C mov eax,dword ptr ds:[esi+C]
002F0952 03C7 add eax,edi
002F0954 5D pop ebp
002F0955 5E pop esi
002F0956 5F pop edi
002F0957 5B pop ebx
002F0958 C3 retn //此处f2 ,下断
F9 ,运行,此时断了。单步f8,来到
0101BB3D 8985 C8120010 mov dword ptr ss:[ebp+100012C8],eax ; NOTEPAD.0100739D
0101BB43 8BF0 mov esi,eax
0101BB45 59 pop ecx
0101BB46 5A pop edx
0101BB47 EB 0C jmp short NOTEPAD.0101BB55
0101BB49 03CA add ecx,edx
0101BB4B 68 00800000 push 8000
0101BB50 6A 00 push 0
0101BB52 57 push edi
0101BB53 FF11 call dword ptr ds:[ecx]
0101BB55 8BC6 mov eax,esi
0101BB57 5A pop edx
0101BB58 5E pop esi
0101BB59 5F pop edi
0101BB5A 59 pop ecx
0101BB5B 5B pop ebx
0101BB5C 5D pop ebp
0101BB5D FFE0 jmp eax //跳到oep
0101BB5F 0000 add byte ptr ds:[eax],al
0101BB61 0000 add byte ptr ds:[eax],al
0100739D 6A 70 push 70 //OEP
0100739F 68 98180001 push PECompac.01001898
010073A4 E8 BF010000 call PECompac.01007568
010073A9 33DB xor ebx,ebx
010073AB 53 push ebx
010073AC 8B3D CC100001 mov edi,dword ptr ds:[10010CC] ; kernel32.GetModuleHandleA
010073B2 FFD7 call edi
010073B4 66:8138 4D5A cmp word ptr ds:[eax],5A4D
010073B9 75 1F jnz short PECompac.010073DA
下面就是DUMP进程,ImportREC修复输入表了。
【北斗 nspack】
【北斗1.4.exe】ESP定理直接搞定
【北斗 3.4.exe】ESP定理直接搞定
【PEncrypt 4.0】
【PEncrypt V4.0.EXE】最后一次异常法
这是一个比较少见的可,最后一次异常发搞定他
两次shift + F9,到这里
0040CCD2 4B dec ebx
0040CCD3 6F outs dx,dword ptr es:[edi]
0040CCD4 6368 69 arpl word ptr ds:[eax+69],bp
0040CCD7 8B4424 04 mov eax,dword ptr ss:[esp+4]
0040CCDB 8B00 mov eax,dword ptr ds:[eax]
这时候看堆栈
在SE句柄上面下断点40CCD7,再次shift+F9,这时候继续单步,很快就到OEP了。
用LoadPE脱壳,然后Import REC修复,这时候还是不可以运行,重新启动LoadPE,设置如下:
然后修复一下,就可以运行了。
这是一个比较陌生的壳,要多种方法不断尝试,特别是SHE是特别麻烦的事。
【SFX 方法脱壳】
直接设置这里,可以对80%压缩壳起作用,部分加密壳也可以,不过对于acprotect ,asprotect等强壳无效
【yoda's cryptor 1.2脱壳】
【Yoda's Crypter v1.2.98.E.exe】ESP无效了,两次内存断点可以搞定,先对资源段下断点,然后对代码段下断点,就可以到达OEP,IAT修复需要用Import REC的等级修复。
如图:
<注:尽量使用没有太多插件的od,不然有时候od会出现一些异常,如果用跟踪等级3,可以每次只选几个,反复进行,就不会死机了>
【tElock 脱壳】
【tElock.exe】
第一种方法:最后一次异常法
最后一次异常法,一共有21次异常(不断shift+F9)知道运行起来,重新载入od,20次忽略异常,就可以到最后一次异常处
看堆栈里面的内容,到0040D7FB出下断点,shift+F9,运行到这里,所有的SHE都跳过了,然后就一直单步,如果有pushad或者popad这两个指令,特别关注一下,很快就可以到OEP。
一直运行到这里,跟随,到达OEP
0040D7AF 61 popad
0040D7B0 - FF6424 D0 jmp dword ptr [esp-30] ; tElock.004010CC
接着就是修复IAT了,tElock的IAT是比较恶心的,记得很多人说过Import REC在用lever 3的时候会死机,其实这个和od有关,这时候如果直接打开一个新的tElock.exe,然后Import REC载入的进程不要和OD公用一个,这个问题集就不存在了,如果还是会死,那么就几个几个修复,最后有四个无效的,直接剪切掉就行了。
【PETITE脱壳】
【PETITE.98.E.exe】
这个壳可以用ESP定理,但是这里有点不一样
pushfw
pushad
对应
popad
pushfw
运行到这里pushad的就结束了,查看ESP,下内存断点。搞定
【PEtite 2.x.exe】同上ESP定理搞定。
【ESP定律 OR 两次内存断点 配合寻找OEP】
一.准备知识
在我们开始讨论ESP定律之前,我先给你讲解一下一些简单的汇编知识。
1.call
这个命令是访问子程序的一个汇编基本指令。也许你说,这个我早就知道了!别急请继续看完。call真正的意义是什么呢?我们可以这样来理解:
1.向堆栈中压入下一行程序的地址;
2.JMP到call的子程序地址处。
例如:
00401029.E8 DA240A00 call 004A3508
0040102E.5A pop edx
在执行了00401029以后,程序会将0040102E压入堆栈,然后JMP到004A3508地址处!
也就是压入下一个EIP的值
2.RETN
与call对应的就是RETN了。对于RETN我们可以这样来理解:
1.将当前的ESP中指向的地址出栈;
2.JMP到这个地址。
这个就完成了一次调用子程序的过程。在这里关键的地方是:如果我们要返回父程序,则当我们在堆栈中进行堆栈的操作的时候,一定要保证在RETN这条指令之前,ESP指向的是我们压入栈中的地址。这也就是著名的“堆栈平衡”原理!
3.狭义ESP定律
ESP定律的原理就是“堆栈平衡”原理。
让我们来到程序的入口处看看吧!
1.这个是加了ASPACK壳的入口时各个寄存器的值!
EAX 00000000
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 0040D000 ASPACK.<ModuleEntryPoint>
2.这个是ASPACK壳JMP到OEP后的寄存器的值!
EAX 004010CC ASPACK.004010CC
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 004010CC ASPACK.004010CC
呵呵~是不是除了EIP不同以外,eax保存当前OEP值,其他都一模一样啊!
为什么会这样呢?我们来看看
0040D000 A> 60 pushad //注意这里ESP=0012FFC4
0040D001 E8 00000000 call ASPACK.0040D006 //ESP=0012FFA4
PUSHAD就是把所有寄存器压栈!我们在到壳的最后看看:
0040D558 61 popad //ESP=0012FFA4
0040D559 75 08 jnz short ASPACK.0040D563 //注意这里ESP=0012FFC4
也就是说当我们对ESP的0012FFA4下硬件访问断点之后。当程序要通过堆栈访问这些值
,从而恢复原来寄存器的值,准备跳向苦苦寻觅的OEP的时候,OD帮助我们中断下来。
小结:我们可以把壳假设为一个子程序,当壳把代码解压前和解压后,他必须要做的是遵循堆栈平衡的原理。
因为大家对ESP理解各有异同,但是,大同小异!一般理解可以为:
1、在命令行下断hr esp-4(此时的ESP就是OD载入后当前显示的值)
2、hr ESP(关键标志下一行代码所指示的ESP值(单步通过))
5.总结
现在我们可以轻松的回答一些问题了。
1.ESP定律的原理是什么?
堆栈平衡原理。
2.ESP定律的适用范围是什么?
几乎全部的压缩壳,部分加密壳。只要是在JMP到OEP后,ESP=0012FFC4的壳,理论上我们都可以使用。但是在何时下断点避开校验,何时下断OD才能断下来,这还需要多多总结和多多积累。
3.是不是只能下断12FFA4的访问断点?
当然不是,那只是ESP定律的一个体现,我们运用的是ESP定律的原理,而不应该是他的具体数值,不能说12FFA4,或者12FFC0就是ESP定律,他们只是ESP定律的一个应用罢了!
二 内存断点
1、要解决的问题是:
1.什么是内存断点?
2 .如何在寻找OEP时使用内存断点。
2、内存断点寻找OEP的原理
首先,在OD中内存断点和普通断点(F2下断)是有本质区别的。
内存断点等效于命令bpm,他的中断要用到DR0-DR7的调试寄存器,也就是说OD通过这些DR0-DR7的调试寄存器来判断是否断下普通断点(F2下断)等效于bpx,他是在所执行的代码的当前地址的一个字节修改为CC(int3)。当程序运行到int3的时候就会产生一个异常,而这个异常将交给OD处理,把这个异常给EIP-1以后,就正好停在了需要的中断的地方(这个根据系统不同会不一样),同时OD在把上面的int3修改回原来的代码。
内存断点分为:内存访问断点,内存写入断点。
我们知道,在程序运行的时候会有3种基本的状态产生:读取-->写入-->执行。
004AE242 A1 00104000 mov eax,dword ptr ds:[004AE24C] //004AE24C处的内存读取
004AE247 A3 00104000 mov dword ptr ds:[004AE24C],eax //004AE24C处的内存写入
004AE24C 83C0 01 add eax,1 //004AE24C处的内存执行
1.当对004AE24C下内存访问断点的时候,可以中断在004AE242也可以中断在004AE247。
2.当对004AE24C下内存写入断点的时候,只能中断在004AE247。
3.当执行004AE24C的时候,只能中断在004AE24C
到这里你可能不明白了,为什么内存访问断点能中断在004AE247这一句对004AE24C的写入,而且还能中断在004AE24C的执行呢?其实很简单,我们只要仔细体会一下“内存访问”这四个字的含义遍可以知道,当我们对004AE24C进行读取的时候需要“访问”他吧,当我对004AE24C进行写入的时候也需要“访问”他吧!!当然我们要执行内存地址004AE24C的代码的时候也是还是要“访问”他的!
所以我们不难得出下面的结论:
1.内存写入中断的地方,一定是也可以用内存访问中断。
2.内存执行的地方,也可以用内存访问中断。
如果这时你认为,那么内存写入岂不是没用了。呵呵~那我要告诉你当然不是,如果你想快速的准确的定位到004AE247这一行的时候,那么他就大有作用了!
总结一下:内存断点不修改原代码,不会像普通断点那样因为修改代码被程序校验而导致中断失败;对于区段的访问只是区域大了一点,其原理和上面分析的三行代码是一样的。
ii.如何使用内存断点来寻找OEP呢?
要回答这个问题首先要回答这一个问题:壳是如何解压代码的?
正如我们知道的,壳如果要把原来加密或压缩的代码运行起来就必须要解压和解密原来的代码。而这一个过程我们难道不能将他看做是对代码段(code段)的写入吗?好了,解压完毕了。我们要从壳代码的区段JMP到原来的代码段的时候,难道不正是对代码段(code段)的执行吗?
理清了上面的关系就好办了,那么如果载入OD后,我们直接对code段下内存访问断点的时候,一定会中断在壳对code段的写入的代码的上面,就像上面的004AE247的这一行。而如果当他把code段的代码全部解压解密完毕了以后,JMP到OEP的时候,我们是不是还可以停在OEP的代码上面呢?而且每按下F9都会中断,因为这时code段在执行中哦!
而如果你还要继续问我为什么一定要到那个地方才可以下断呢?我难道不可以一开始就下断吗?
正入我上面所说的,如果你在前面下断很可能壳对code段还没解压完毕呢,这时如果你不停的按F9,你将会看到OD的下方不断的在提示你,“对401000写入中断”“对401002写入中断”“对401004写入中断”.......如果你不介意按F9到他把正个code段写完的话,我除了同情你的“F9”以外,没什么其他的意见!
那么我们就没有别更快一点的办法了吗?
有的!那就是我们呼之欲出的两次内存断点办法。
怎么理解两次内存断点呢?
让我来做一个假设吧,假设我是一个壳的作者。一个EXE文件的有code段,data段,rsrc段.....依次排列在你的内存空间中,那么我会怎么解码呢?呵呵~我比较笨一点,我会先将code段解码,然后再将data段解压,接着是rsrc段......那么你不难发现,只要你在data断或者rsrc段下内存访问断点,那么中断的时候code段就已经解压完毕了。这时我们再对code段下内存访问断点,不就可以到达OEP了吗?
这里注意上面虽然下了两次内存访问断点,但是本质是不一样的,目的也是不一样的。
1.对data段下内存访问断点而中断是因为内存写入中断,目的是断在对对data段的解压时,这时壳要对data段写数据,但是code段已经解压 完毕。
2.对code段下内存访问断点而中断是因为内存执行中断,目的当然就是寻找OEP了。
总结一下:如果我们知道壳在什么地方对code段解压完毕我们就可以使用内存断点,找到OEP。如果不知道,那么我们就依靠2次内存断点去找,如果还不行就用多次内存断点。总之明白了原理在多次的内存断点其实都一样。从这个过程中我们了解的是壳在对区段解码的顺序!
【附加数据处理方法】
【Overlay.exe】
ESP定理马上可以找到OEP
资源需要修复
算出文件的结尾开始地址:00000400+0000C600=0000CA00,把后面的数据完全复制黏贴在新的文件上面就行了。
【自校验的去除】脱壳之后启动之后会自动退出,重新载入分析一下就可以了,技巧是createfile下断点。
【EncryptPE】【反外挂服务器.exe】
忽略所有异常,ESP定理,不过异常的种类比OD配置的多一些,前人的经验,多了如下异常:
这些异常还不是很清楚ANTI是如何触发的,不过忽略之后确实有用。OEP一下子就找到了,然后修复一下数据,搞定。
【Armadillo 1.xx - 2.xx 单线程】
【XDeskWeather】
*******************************************************************************************
1、1.xx--2.xx&单线程&标准方式==========》目标程序“XDeskWeather 3.6(桌面天气秀)”
现在任务管理器中查看是否双进程
*******************************************************************************************
方法:2次断点法,即是:
bp GetModuleHandleA/he GetModuleHandleA/bp GetModuleHandleA+5/he GetModuleHandleA+5
bp GetCurrentThreadId
这种断点是为了解决IAT加密,是一种通用技巧。
*******************************************************************************************
OD,载入。。。。。
004FD379 X>/$ 55 push ebp //程序入口
004FD37A |. 8BEC mov ebp,esp
004FD37C |. 6A FF push -1
下断he GetModuleHandleA,F9运行,注意看堆栈!
7C80B529 k> 8BFF mov edi,edi ;ntdll.7C930738 //停在这里
7C80B52B 55 push ebp
7C80B52C 8BEC mov ebp,esp
7C80B52E 837D 08 00 cmp dword ptr ss:[ebp+8],0
***********************************
每一次F9运行时候,所出现的堆栈情况!
***********************************
0012FF38 004FD441 /CALL 到 GetModuleHandleA 来自 XDeskWea.004FD43B
0012FF3C 00000000 \pModule = NULL
0012FF40 00000000
0012ED48 77F45BB0 /CALL 到 GetModuleHandleA 来自 SHLWAPI.77F45BAA
0012ED4C 77F44FF4 \pModule = "KERNEL32.DLL"
0012ED50 00000001
0012EC88 5D175334 /CALL 到 GetModuleHandleA 来自 COMCTL32.5D17532E
0012EC8C 5D175380 \pModule = "kernel32.dll"
0012EC90 5D1E3AB8 COMCTL32.5D1E3AB8
0012F55C 004F3073 /CALL 到 GetModuleHandleA 来自 XDeskWea.004F306D
0012F560 00000000 \pModule = NULL
0012F564 7C939BA0 返回到 ntdll.7C939BA0 来自 ntdll.7C9399B5
0012C280 00C15331 /CALL 到 GetModuleHandleA 来自 00C1532B //到这一次的时间缓冲有点大
0012C284 0012C3BC \pModule = "kernel32.dll"
0012C288 00000002
此时,取消断点,Alt+F9返回!
00C15331 8B0D 60D8C300 mov ecx,dword ptr ds:[C3D860] //返回到这里
00C15337 89040E mov dword ptr ds:[esi+ecx],eax
00C1533A A1 60D8C300 mov eax,dword ptr ds:[C3D860]
00C1533F 393C06 cmp dword ptr ds:[esi+eax],edi
00C15342 75 16 jnz short 00C1535A
00C15344 8D85 B4FEFFFF lea eax,dword ptr ss:[ebp-14C]
00C1534A 50 push eax
00C1534B FF15 B850C300 call dword ptr ds:[C350B8] ; kernel32.LoadLibraryA
00C15351 8B0D 60D8C300 mov ecx,dword ptr ds:[C3D860]
00C15357 89040E mov dword ptr ds:[esi+ecx],eax
00C1535A A1 60D8C300 mov eax,dword ptr ds:[C3D860]
00C1535F 393C06 cmp dword ptr ds:[esi+eax],edi
00C15362 0F84 AD000000 je 00C15415 //Magic Jump,改jmp!
00C15368 33C9 xor ecx,ecx
00C1536A 8B03 mov eax,dword ptr ds:[ebx]
00C1536C 3938 cmp dword ptr ds:[eax],edi
00C1536E 74 06 je short 00C15376
此时第一个断点的任务完成!
********************************************************************************************
下断bp GetCurrentThreadId,F9,注意观察堆栈!
7C809737 k> 64:A1 18000000 mov eax,dword ptr fs:[18] //停在这里
7C80973D 8B40 24 mov eax,dword ptr ds:[eax+24]
7C809740 C3 retn
*************
0012BB40 73391E36 /CALL 到 GetCurrentThreadId 来自 73391E30
0012BB44 00000001
0012BB48 73391C1A 返回到 73391C1A 来自 73391DE2
0012BB4C 73391B60 返回到 73391B60 来自 73391B8C
0012BB20 7339353F /CALL 到 GetCurrentThreadId 来自 73393539
0012BB24 00000000
0012BB28 734A0470
0012F5A8 00C2CF2D /CALL 到 GetCurrentThreadId 来自 00C2CF27 //到这一次的时间缓冲有点大
0012F5AC 0012FF2C
0012F5B0 00000000
此时,取消断点,Alt+F9返回!
00C2CF2D A3 F018C400 mov dword ptr ds:[C418F0],eax //返回到了这里!
00C2CF32 E8 2487FEFF call 00C1565B
00C2CF37 6A 00 push 0
00C2CF39 E8 4BD9FEFF call 00C1A889
00C2CF3E 59 pop ecx
00C2CF3F E8 7D39FFFF call 00C208C1
00C2CF44 8BF8 mov edi,eax
00C2CF46 A1 E018C400 mov eax,dword ptr ds:[C418E0]
00C2CF4B 8B48 74 mov ecx,dword ptr ds:[eax+74]
00C2CF4E 3348 5C xor ecx,dword ptr ds:[eax+5C]
00C2CF51 3308 xor ecx,dword ptr ds:[eax]
00C2CF53 03F9 add edi,ecx
00C2CF55 8B0E mov ecx,dword ptr ds:[esi]
00C2CF57 85C9 test ecx,ecx
00C2CF59 75 2E jnz short 00C2CF89
00C2CF5B 8B78 5C mov edi,dword ptr ds:[eax+5C]
00C2CF5E E8 5E39FFFF call 00C208C1
00C2CF63 8B0D E018C400 mov ecx,dword ptr ds:[C418E0] ; XDeskWea.0051F258
00C2CF69 FF76 14 push dword ptr ds:[esi+14]
00C2CF6C 8B51 74 mov edx,dword ptr ds:[ecx+74]
00C2CF6F FF76 10 push dword ptr ds:[esi+10]
00C2CF72 33D7 xor edx,edi
00C2CF74 3311 xor edx,dword ptr ds:[ecx]
00C2CF76 FF76 0C push dword ptr ds:[esi+C]
00C2CF79 03C2 add eax,edx
00C2CF7B 8B51 78 mov edx,dword ptr ds:[ecx+78]
00C2CF7E 3351 14 xor edx,dword ptr ds:[ecx+14]
00C2CF81 33D7 xor edx,edi
00C2CF83 2BC2 sub eax,edx
00C2CF85 FFD0 call eax
00C2CF87 EB 25 jmp short 00C2CFAE
00C2CF89 83F9 01 cmp ecx,1
00C2CF8C 75 22 jnz short 00C2CFB0
00C2CF8E FF76 04 push dword ptr ds:[esi+4]
00C2CF91 FF76 08 push dword ptr ds:[esi+8]
00C2CF94 6A 00 push 0
00C2CF96 E8 2639FFFF call 00C208C1
00C2CF9B 50 push eax
00C2CF9C A1 E018C400 mov eax,dword ptr ds:[C418E0]
00C2CFA1 8B48 78 mov ecx,dword ptr ds:[eax+78]
00C2CFA4 3348 5C xor ecx,dword ptr ds:[eax+5C]
00C2CFA7 3348 14 xor ecx,dword ptr ds:[eax+14]
00C2CFAA 2BF9 sub edi,ecx
00C2CFAC FFD7 call edi //直接到这下“硬件执行”断点,F9,取消断点,F7进入
004D12D4 55 push ebp //到这里了,OEP!LordPE-纠正映像-Dump!
004D12D5 8BEC mov ebp,esp
004D12D7 83C4 F0 add esp,-10
004D12DA B8 0C0E4D00 mov eax,XDeskWea.004D0E0C
004D12DF E8 004EF3FF call XDeskWea.004060E4
004D12E4 A1 B06E4D00 mov eax,dword ptr ds:[4D6EB0]
004D12E9 8B00 mov eax,dword ptr ds:[eax]
004D12EB E8 08C0F9FF call XDeskWea.0046D2F8
004D12F0 E8 D7E5FFFF call XDeskWea.004CF8CC
004D12F5 A1 B06E4D00 mov eax,dword ptr ds:[4D6EB0]
004D12FA 8B00 mov eax,dword ptr ds:[eax]
OD,不要关!打开import--选择进程--OEP输入D12D4--自动搜索IAT--获取输入表--显示无效函数--CUT!
这个技巧使用大部分Armadillo版本
【Armadillo 3.78 - 4.xx】
【Jxt】
【ArmaG3ddon v1.9】支持3.78~ 7.7
任务管理器一看,双进程。
遇到过Armadillo的朋友应该知道,它是有点变态的。。中文意思“穿山甲”,可想而知,是很难脱的。
首先介绍一下Armadillo的一些版本以及保护方式、线程情况吧
A:版本
1.xx--2.xx
3.0a--3.61
3.75
3.78
4.x
B:保护方式
标准方式
非标准方式======>Armadillo CopyMem-ll +Debug-Blocker
C:线程
单线程
双线程
上面三种特征都可以两两组合,或者是三三组合。。变化方式之多,可见一斑!下面我将做下总结!希望能够起到抛砖引玉的作用!
*******************************************************************************************
保护方式判断:如果你用脱标准壳的方法去脱不行的话,那么就很有可能是非标准版啦。
线程的判断:方法1、运行程序,打开系统的任务管理器,看看有几个同名进程咯。
方法2、运行程序,打开LordPE,同样是看看有几个同名进程。一个的话就是单进程,两个就是双进程。
*******************************************************************************************
脱壳前的准备:(*****为了节约时间,我在后面将不做说明了,大家要记住!*****)
1、OD设置忽略所有的异常,用隐藏插件隐藏OD!
2、思想准备:Armadillo对断点的检测非常严格,所以我们在设置断点的时候要尽量去使用“硬件执行”
3、概念准备:使用PEID的Armadillo的版本检测一般没那么准确,我倒是发现fi的版本检测还是要强一些
4、Magic Jump:跳转的跨越段一般比较大!(返回时机一定要对!)
5:返回的时机:1、返回的地址是系统领空
2、Shift+F9过程当中,时间缓冲比较大才停下(得自己体会一下)
*******************************************************************************************
吉祥天传世外挂 1.0.0.1
首先PEID查壳是Armadillo 3.78 -> Silicon Realms Toolworks,其实是4.X的版本,而且是个双线程的标准壳!
下面具体的步骤就不写了,就写一些重点吧!
我是在2000下操作的,不知道在XP下是不是好搞点,呵呵
忽略所有异常,手动添加C000001E,E06D7363异常。隐藏OD!
一、双变单(使程序把自己当成子进程运行)
bp OpenMutexA
Ctrl+G:00401000
00401000 60 pushad
00401001 9C pushfd
00401002 68 A0FD1200 push 12FDA0 ; ASCII "44C::DA47D45903"
00401007 33C0 xor eax,eax
00401009 50 push eax
0040100A 50 push eax
0040100B E8 E694A677 call KERNEL32.CreateMutexA
00401010 9D popfd
00401011 61 popad
00401012 - E9 8F9FA777 jmp KERNEL32.OpenMutexA
60 9C 68 A0 FD 12 00 33 C0 50 50 E8 71 8D A8 77 9D 61 E9 74 8E A8 77
二、避开Anti
he OutputDebugStringA
中断2次!
选中%s%之类的字符,点右键->二进制->使用00填充
删除此断点!
三、Magic Jump,避开IAT加密
PS:很奇怪的就是用he GetModuleHandleA+5,却找不到Magic Jump!
bp GetModuleHandleA/he GetModuleHandleA
77E80B1A KE> 55 push ebp //断下,取消这个断点
77E80B1B 8BEC mov ebp,esp
77E80B1D 837D 08 00 cmp dword ptr ss:[ebp+8],0
77E80B21 75 0E jnz short KERNEL32.77E80B31 //F2下断,Shift+F9,断下!注意堆栈!
77E80B23 64:A1 18000000 mov eax,dword ptr fs:[18]
77E80B29 8B40 30 mov eax,dword ptr ds:[eax+30]
77E80B2C 8B40 08 mov eax,dword ptr ds:[eax+8]
001292A4 /0012EBB0
001292A8 |01066AC2 返回到 01066AC2 来自 KERNEL32.GetModuleHandleA
001292AC |0107BD6C ASCII "kernel32.dll"
001292B0 |0107DDAC ASCII "VirtualAlloc"
001292A4 /0012EBB0
001292A8 |01066ADF 返回到 01066ADF 来自 KERNEL32.GetModuleHandleA
001292AC |0107BD6C ASCII "kernel32.dll"
001292B0 |0107DDA0 ASCII "VirtualFree"
00129008 /001292A8
0012900C |01055A99 返回到 01055A99 来自 KERNEL32.GetModuleHandleA
00129010 |0012915C ASCII "kernel32.dll" //取消断点,返回!
01055A99 8B0D 6C500801 mov ecx,dword ptr ds:[108506C] //返回到这里!
01055A9F 89040E mov dword ptr ds:[esi+ecx],eax
01055AA2 A1 6C500801 mov eax,dword ptr ds:[108506C]
01055AA7 391C06 cmp dword ptr ds:[esi+eax],ebx
01055AAA 75 16 jnz short 01055AC2
01055AAC 8D85 B4FEFFFF lea eax,dword ptr ss:[ebp-14C]
01055AB2 50 push eax
01055AB3 FF15 B8620701 call dword ptr ds:[10762B8] ; KERNEL32.LoadLibraryA
01055AB9 8B0D 6C500801 mov ecx,dword ptr ds:[108506C]
01055ABF 89040E mov dword ptr ds:[esi+ecx],eax
01055AC2 A1 6C500801 mov eax,dword ptr ds:[108506C]
01055AC7 391C06 cmp dword ptr ds:[esi+eax],ebx
01055ACA 0F84 2F010000 je 01055BFF //Magic Jump,改jmp!
01055AD0 33C9 xor ecx,ecx
01055AD2 8B07 mov eax,dword ptr ds:[edi]
01055AD4 3918 cmp dword ptr ds:[eax],ebx
01055AD6 74 06 je short 01055ADE
01055AD8 41 inc ecx
01055AD9 83C0 0C add eax,0C
往下拉,找如此类似的序列(一个jnz,一个jmp,两个salc/Magic Jump)
也可以这样做:Ctrl+F在当前位置查找命令: salc
01055C0E ^\0F85 49FEFFFF jnz 01055A5D
01055C14 EB 03 jmp short 01055C19 //F2下断,Shift+F9,断下!取消断点!
01055C16 D6 salc
01055C17 D6 salc
重要:断下后,记得要撤消Magic Jump处的修改!
为何要这样做?我发现程序在下面会依据原先的代码进行解码,
以前下 硬件断点 操作没有修改原代码,所以解码正确。
而直接修改Magic Jump后改变了原先的代码,导致解码不正确而异常出错!
现在我们在解码以前恢复原先的代码,因此就不会再出错了!
此时,打开内存镜像,在00401000段下断,Shift+F9直达OEP!
01070324 8B0C3A mov ecx,dword ptr ds:[edx+edi] //来到这里,F8
01070327 5B pop ebx
01070328 03D7 add edx,edi
0107032A A1 A4100801 mov eax,dword ptr ds:[10810A4]
0107032F 3148 70 xor dword ptr ds:[eax+70],ecx
01070332 A1 A4100801 mov eax,dword ptr ds:[10810A4]
01070337 3148 70 xor dword ptr ds:[eax+70],ecx
0107033A A1 A4100801 mov eax,dword ptr ds:[10810A4]
0107033F 8B16 mov edx,dword ptr ds:[esi]
01070341 8B88 8400000>mov ecx,dword ptr ds:[eax+84]
01070347 3348 60 xor ecx,dword ptr ds:[eax+60]
0107034A 3348 34 xor ecx,dword ptr ds:[eax+34]
0107034D 030D BC10080>add ecx,dword ptr ds:[10810BC] ; FlyWoool.00400000
01070353 85D2 test edx,edx
01070355 75 1E jnz short 01070375
01070357 8B90 8800000>mov edx,dword ptr ds:[eax+88]
0107035D FF76 18 push dword ptr ds:[esi+18]
01070360 3390 8400000>xor edx,dword ptr ds:[eax+84]
01070366 FF76 14 push dword ptr ds:[esi+14]
01070369 3350 40 xor edx,dword ptr ds:[eax+40]
0107036C FF76 10 push dword ptr ds:[esi+10]
0107036F 2BCA sub ecx,edx
01070371 FFD1 call ecx
01070373 /EB 23 jmp short 01070398
01070375 |83FA 01 cmp edx,1
01070378 |75 21 jnz short 0107039B
0107037A |FF76 04 push dword ptr ds:[esi+4]
0107037D |8B90 8800000>mov edx,dword ptr ds:[eax+88]
01070383 |3390 8400000>xor edx,dword ptr ds:[eax+84]
01070389 |FF76 08 push dword ptr ds:[esi+8]
0107038C |3350 40 xor edx,dword ptr ds:[eax+40]
0107038F |6A 00 push 0
01070391 |FF76 0C push dword ptr ds:[esi+C]
01070394 |2BCA sub ecx,edx
01070396 |FFD1 call ecx ; FlyWoool.004B79A6 //F7进去!直接到达OEP!
004B79A6 6A 60 push 60 //OEP!
004B79A8 68 00235D00 push FlyWoool.005D2300
004B79AD E8 26070000 call FlyWoool.004B80D8
004B79B2 BF 94000000 mov edi,94
004B79B7 8BC7 mov eax,edi
004B79B9 E8 E2D1FFFF call FlyWoool.004B4BA0
004B79BE 8965 E8 mov dword ptr ss:[ebp-18],esp
004B79C1 8BF4 mov esi,esp
004B79C3 893E mov dword ptr ds:[esi],edi
004B79C5 56 push esi
004B79C6 FF15 A4445B00 call dword ptr ds:[5B44A4] ; KERNEL32.GetVersionExA
004B79CC 8B4E 10 mov ecx,dword ptr ds:[esi+10]
004B79CF 890D A4367C00 mov dword ptr ds:[7C36A4],ecx
004B79D5 8B46 04 mov eax,dword ptr ds:[esi+4]
LordPE纠正大小Dump!打开Import 1.6,OEP填B79A6,有14个无效指针,全部CUT,正常运行!
【AcProtect】
【AcProtect 123.exe】
本例不处理stolen code ,相对简单
---------------------------------------------------------------------------------
Acprotect1.X之VB程序的处理(高一点的版本。。。。。)
目标程序:估计是个游戏外挂登陆器(网上别人求脱的^_^)
********************************************************************************************
首先Peid查壳,Nothing found *!再看EP区段.perplex,原来是Acprotect1.X版加的壳。
因为是VB程序(跟踪过程中很容易看出来的)
Stolen Code很简单,没有必要苦苦跟踪,VB的IAT加密目前大部分加密软件都是有心无力的。
OD异常设置不忽略内存异常,隐藏OD(估计是高一点版本的Acprotect,因为我有几次隐藏了OD还退出)
这时候反复重新载入几次之后就行了
********************************************************************************************
OD载入程序
00422000 123.<Mod> 55 push ebp //入口
00422001 50 push eax
00422002 E8 01000000 call 123.00422008
00422007 - 7D 83 jge short 123.00421F8C
00422009 C40458 les eax,fword ptr ds:[eax+ebx*2]
0042200C F8 clc
0042200D 66:81E6 4858 and si,5848
F9一下,到最后一次典型异常!
0043374D CD 01 int 1 //最后一次典型异常!注意堆栈!
0043374F 40 inc eax
00433750 40 inc eax
00433751 0BC0 or eax,eax
00433753 75 05 jnz short 123.0043375A
00433755 90 nop
***********************************************
堆栈提示:
0012FF84 0012FFE0 指针到下一个 SEH 记录
0012FF88 00433731 SE 句柄 //右键--转存中跟随--下内存访问断点
0012FF8C 00948A20
***********************************************
下好断点后,Shift+F9运行!
00433731 8B5C24 0C mov ebx,dword ptr ss:[esp+C] //运行到这里,F2下断,Shift+F9运行
00433735 8383 B8000000 02 add dword ptr ds:[ebx+B8],2
0043373C 33C0 xor eax,eax
0043373E C3 retn
00433781 8B048E mov eax,dword ptr ds:[esi+ecx*4] //运行到这里,F2下断,Shift+F9运行
00433784 8B5C8E 04 mov ebx,dword ptr ds:[esi+ecx*4+4>
00433788 2BC3 sub eax,ebx
0043378A C1C8 05 ror eax,5
0043378D 2BC2 sub eax,edx
0043378F 81C2 43A18EAB add edx,AB8EA143
00433795 89048E mov dword ptr ds:[esi+ecx*4],eax //Shift+F9运行后就跳到这里
00433798 49 dec ecx
00433799 ^ EB E1 jmp short 123.0043377C
0043379B 61 popad
0043379C 61 popad
0043379D C3 retn //取消所有的断点[2次F2(INT3断点),1次内存访问断点],F4下来!
************************************************
因为是VB程序,Stolen Code很简单,没必要苦苦跟踪
VB的IAT加密目前大部分加密软件都是有心无力的。
************************************************
鉴于这样。。
打开内存镜像
内存镜像,项目 21
地址=00401000 //F2下断,Shift+F9运行
大小=0001D000 (118784.)
Owner=123 00400000
区段=.text
包含=code
类型=Imag 01001002
访问=R
初始访问=RWE
00401B44 - FF25 9C114000 jmp dword ptr ds:[40119C] ; MSVBVM60.SetMemEvent
00401B4A - FF25 7C114000 jmp dword ptr ds:[40117C] ; MSVBVM60.ThunRTMain //运行到这注意堆栈!
00401B50 47 inc edi
00401B51 6B2B 2E imul ebp,dword ptr ds:[ebx],2E
00401B54 36:E6 96 out 96,al
00401B57 09E5 or ebp,esp
00401B59 73 00 jnb short 123.00401B5B
**********************************************************************
堆栈提示:
0012FFD8 00438CC9 返回到 123.00438CC9 来自 123.00401B4A
0012FFDC 00402C98 ASCII "VB5!6&vb6chs.dll" //要00402C98这个地址
0012FFE0 FFFFFFFF SEH 链尾部
**********************************************************************
现在开始简单处理了。。。
汇编下
00401B4A - FF25 7C114000 jmp dword ptr ds:[40117C] ; MSVBVM60.ThunRTMain
00401B50 68 982C4000 push 123.00402C98 ; ASCII "VB5!6&vb6chs.dll"
00401B55 E8 F0FFFFFF call 123.00401B4A ; jmp to MSVBVM60.ThunRTMain
00401B5A 90 nop
00401B5B 0000 add byte ptr ds:[eax],al
FF 25 7C 11 40 00 68 98 2C 40 00 E8 F0 FF FF FF 90
用OD插件脱壳(纠正OEP为1B50),不用修复直接就可以运行了!
Microsoft Visual Basic 5.0 / 6.0
********************************************************************************************
后记:对Acprotect壳的处理套路大概就是这样了,对这个程序我们没有去处理stolen Code。。。所以显得简单了一些!
【AsProtect 】
【AsProtect emailcaster.exe】
ASProtect 1.23 RC1 -> Alexey Solodovnikov
没有注册的时候有试用提示!
1、OD载入之后忽略除了内存访问之外的所有异常,隐藏OD!Shift+F9,注意堆栈!
0012FF54 018032F0
0012FF58 01811810 ASCII "6uob9ACQoUA=" //硬盘指纹
当第2次出现硬盘指纹的时候,在00401000下F2断点,Shift+F9!
00480650 55 push ebp
00480651 8BEC mov ebp,esp
00480653 8B45 08 mov eax,dword ptr ss:[ebp+8]
00480656 A3 EC7E4800 mov dword ptr ds:[487EEC],eax //487EEC就是保存注册名的位置
0048065B 5D pop ebp
0048065C C2 0400 retn 4
继续Shift+F9运行来到最后一次异常!
01802CD1 3100 xor dword ptr ds:[eax],eax //最后一次异常
01802CD3 64:8F05 0000000>pop dword ptr fs:[0]
01802CDA 58 pop eax
01802CDB 833D 7C6D8001 0>cmp dword ptr ds:[1806D7C],0
01802CE2 74 14 je short 01802CF8
01802CE4 6A 0C push 0C
01802CE6 B9 7C6D8001 mov ecx,1806D7C
01802CEB 8D45 F8 lea eax,dword ptr ss:[ebp-8]
01802CEE BA 04000000 mov edx,4
01802CF3 E8 54E1FFFF call 01800E4C
01802CF8 FF75 FC push dword ptr ss:[ebp-4]
01802CFB FF75 F8 push dword ptr ss:[ebp-8]
01802CFE 8B45 F4 mov eax,dword ptr ss:[ebp-C]
01802D01 8338 00 cmp dword ptr ds:[eax],0
01802D04 74 02 je short 01802D08
01802D06 FF30 push dword ptr ds:[eax]
01802D08 FF75 F0 push dword ptr ss:[ebp-10]
01802D0B FF75 EC push dword ptr ss:[ebp-14]
01802D0E C3 retn //F2下断,Shift+F9运行,注意堆栈
0012FF5C 018148AC
0012FF60 00400000 ASCII "MZP"
0012FF64 C9F5F162
0012FF68 0012FFA4 //要的就是0012FF68 SHE的地址。
hr 0012FF68,F9运行
01815082 03C3 add eax,ebx ; emailcas.00400000 //来到这里,F8
01815084 894424 1C mov dword ptr ss:[esp+1C],eax
01815088 61 popad
01815089 FFE0 jmp eax //跳到OEP
00486718 55 push ebp //OEP
00486719 8BEC mov ebp,esp
0048671B 83C4 F4 add esp,-0C
0048671E B8 18654800 mov eax,emailcas.00486518
00486723 E8 5401F8FF call emailcas.0040687C
00486728 A1 BC814800 mov eax,dword ptr ds:[4881BC]
0048672D 8B00 mov eax,dword ptr ds:[eax]
以下就是脱壳修复了!
用Import REC等级1修复,然后利用插件修复。这时候程序还是未注册版本
最后是以自己的名字注册了!
还记得487EEC就是保存注册名的位置
在数据段00488360写入 注册名字
载入脱壳后修复的文件
命令行DD 487EEC
24894800
00487EEC 017F3861
00487EF0 0000001E
00487EF4 0000001E
修改成
00487EEC 00488360 ASCII "hack by zhxfl"
00487EF0 FFFFFFFF ;记录注册日期
00487EF4 FFFFFFFF;使用日期之类的。
**************
找块空地
00488FE0 63617243
00488FE4 7942206B
00488FE8 C8FDC820
00488FEC 00D0D0CB shell32.00D0D0CB
另外程序有暗桩,怎么去掉见操作!
载入dump_.exe,然后触发安装,直接跳过异常语句即可。
【AcProtect】
【UltraProtect 1.x.EXE】
这里对stolen code的处理比较特别,不是把stolen code寻找出来,而是找另外一个OEP,保留部分壳的信息。
我们脱壳必须知道一些程序的入口特征,关于这个我会做一个专题的(一般是5种程序),下面就介绍一种:
Visual C++的入口特征
push ebp
mov ebp,esp
sub esp,44
push esi
call dword ptr ds:[<&KERNEL32.GetCommandLineA>] ; [GetCommandLineA
mov esi,eax
mov al,byte ptr ds:[eax]
二进制代码
55 8B EC 83 EC 44 56 FF 15 E0 63 40 00 8B F0 8A 00
此例作为脱壳示例,只是想起到抛砖引玉的作用!
********************************************************************************************带发修行ACProtect v1.21=========>UltraProtect 1.x -> RISCO Software Inc.
********************************************************************************************Od设置不忽略内存异常,其余异常全部忽略
载入,隐藏!
0040D000 U> 60 pushad //入口,F8一下!
0040D001 70 02 jo short UltraPro.0040D005 //注意ESP值(0012FFA4)
0040D003 D3FE sar esi,cl
0040D005 C1D6 12 rcl esi,12
0040D008 FC cld
0040D009 F9 stc
我们下断hr 0012FFA4,F9运行,这里ESP定律要分7对中断
0041E6FF 61 popad //1
0041E700 56 push esi ; ntdll.77F57D70
0041E701 BE A3DE4000 mov esi,UltraPro.0040DEA3
0041E750 60 pushad
0041E751 E8 0ABDFFFF call UltraPro.0041A460
0041E756 E8 00000000 call UltraPro.0041E75B
0041E768 899D AAD24000 mov dword ptr ss:[ebp+40D2AA],ebx
0041E76E 61 popad //2
0041E76F 890F mov dword ptr ds:[edi],ecx
0041E7BF 60 pushad
0041E7C0 E8 9BBCFFFF call UltraPro.0041A460
0041E7C5 E8 34BAFFFF call UltraPro.0041A1FE
0041E7D0 61 popad //3
0041E7D1 8B0B mov ecx,dword ptr ds:[ebx]
0041E7D3 8F05 93DE4000 pop dword ptr ds:[40DE93]
0041E821 60 pushad
0041E822 E8 39BCFFFF call UltraPro.0041A460
0041E827 C685 D0D14000 00 mov byte ptr ss:[ebp+40D1D0],0
0041E82E 61 popad //4
0041E82F FF35 EBDE4000 push dword ptr ds:[40DEEB]
0041E835 57 push edi
0041E87F 60 pushad
0041E880 E8 15DEFFFF call UltraPro.0041C69A
0041E885 61 popad //5
0041E886 8F05 B7DE4000 pop dword ptr ds:[40DEB7] ; UltraPro.0040DF0B
0041E88C FF35 B7DE4000 push dword ptr ds:[40DEB7]
0041E8D6 60 pushad
0041E8D7 E8 5BDBFFFF call UltraPro.0041C437
0041E8DC 61 popad //6
0041E8DD FF35 CFDE4000 push dword ptr ds:[40DECF]
0041E8E3 56 push esi
0041E92D 60 pushad
0041E92E E8 86FDFFFF call UltraPro.0041E6B9
0041E933 61 popad //7
0041E934 8F05 73DE4000 pop dword ptr ds:[40DE73] ; ntdll.77F944A8 //这里就是代发修行的最佳脱壳地点,此时对资源和代码已经完全解压。OD插件,DUMP!
大家可以看出 +++++++以上对应7句保护Call,为什么要算清楚是7句呢?,到伪造入口就明白。+++++++
另外怎么去知道那里才是带发修行的好地方呢?其实很简单~等下你就明白了!(嘿嘿~知道了吧~就是相当于最后一次ESP
分段了!)
F9继续运行!
0041BAAD CD 01 int 1 //中断在这里,取消硬件断点!
0041BAAF 40 inc eax
0041BAB0 40 inc eax
0041BAB1 0BC0 or eax,eax
0041BAB3 75 05 jnz short UltraPro.0041BABA
0041BAB5 90 nop
0041BAB6 90 nop
我们ALT+M 打开内存镜像,在00401000(Code)段F2下断,Shift+F9运行!
004010DD 3C 22 cmp al,22 //到这里了,伪OEP!
004010DF 75 1B jnz short UltraPro.004010FC
004010E1 56 push esi
004010E2 FF15 F4644000 call dword ptr ds:[4064F4] ; UltraPro.0040D4D6
004010E8 8BF0 mov esi,eax
我们按住Crtl+向上箭头,往上翻看(防止代码混乱-找真OEP!)
004010CC 95 xchg eax,ebp //真OEP,但是代码被抽取了!
004010CD 61 popad
004010CE 2E:EF out dx,eax
004010D0 D1AD 26477503 shr dword ptr ss:[ebp+3754726],1
004010D6 8730 xchg dword ptr ds:[eax],esi
004010D8 3C A2 cmp al,0A2
004010DA ^ 78 84 js short UltraPro.00401060
004010DC 7F 3C jg short UltraPro.0040111A
现在就是还原代码了~
55 8B EC 83 EC 44 56 FF 15 E0 63 40 00 8B F0 8A 00
二进制粘帖!(其实这一步不用这么做的^_^,呵呵~如果用其他方法就得这么做了!)
这里,我们获取真、伪OEP只是方便修复IAT,其实壳早就在0041E934处解码完毕了!
关掉OD,打开加壳程序(因为我们使用跟踪等级3修复的时候,如果开着OD,ImportREC会死掉的!)
运行ImportREC,选择这个进程。把OEP改为000010CC,点IT AutoSearch,点“Get Import”,指针部分有效,用跟踪等级3全部修复,把OEP改为1E934(0041E934-00400000),修复程序,正常运行。
PS:如果还是死掉的话~我们就分段修复吧~一回少修复一点!
脱壳文件显示Nothing found *呵呵~其实壳已经脱掉了,这样的显示是因为加壳的缘故了~很正常!!
【ASProtect 1.23 RC4 - 1.3.08.24 -> Alexey Solodovnikov 以壳脱壳】
【以壳脱壳原理】
1.以壳解壳的原理I.什么是stolen code。===================== 关于stolen bytes ===================== 稍微说明一下: 每一种编译工具例如 : VC++ , Delphi , Borland , etc.. 在OEP有一个唯一的/相同的PE头 其中的一些是这样的:
Push EBP MOV Ebp,Esp Add ESP , -010 Mov EAX, SOME_VALUE
(共11bytes) 或者:
Push EBP MOV Ebp,Esp ;* Add ESP , -010 ;**Push EBX ;***Push ESi Push EDi Mov EAX, SOME_VALUE ;****
(共14 bytes)
1.对于*的部分原程序的OEP,通常是一开始以 Push EBP 和MOV Ebp,Esp这两句开始的,不用我多说大家也知道这两句的意思是以EBP代替ESP,作为访问堆栈的指针。为什么要这样呢?为什么几乎每个程序都是的开头能?因为如果我们写过C等函数的时候就应该清楚,程序的开始是以一个主函数main()为开始的,而函数在访问的过程中最重要的事情就是要确保堆栈的平衡,而在win32的环境下保持平衡的办法是这样的:1.让EBP保存ESP的值;2.在结束的时候调用mov esp,ebp pop ebp retn或者是leaveretn两个形式是一个意思。这样做的好处是不用考虑ESP等于多少,PUSH了多少次,要POP多少次了,因为我们知道EBP里面放的是开始时候的ESP值。
2.对于**的部分Add ESP , -010这种代码的意思是在堆栈区域开辟一块区域保存和使用局部变量,用EBP-XX来调用。
3.对于***的部分
在下来就是保存寄存器的初始值。
4.对于****的部分
初始化寄存器。
小节:我们知道了这就是程序在编译后程序OEP的一般形式,而某些壳在处理OEP的代码时,把这些固定的代码nop掉,然后把他们放到壳代码的空间里面(而且还常伴随着花指令)!使原程序的开始从壳空间开始,然后再JMP回程序空间。如果我们脱掉壳了以后,这一部分就会遗失,也就达到了反脱壳的目的。这就是stolen code技术,或者更确切的说是stolen OEP code技术。
II.Replace Code
这是一种将原程序代码抽出,放到壳代码中执行的技术。应该就是一般说的SDK(Software Development Kit)技术。(其实我也不是很懂^^)
怎么实现的不清楚,但是他是如何体现出来的呢?
当你脱完壳了以后,运行发现提示“XXXXXX处不易读取”十有八九就是因为采用了SDK技术。因为当我们脱壳后这部分代码都没有了,我们怎么能读取呢?
总之我把replace code看成是又一种形式的stolen code,他偷掉的是程序中的的code。
III.以壳解壳的提出 上面的两种反脱壳的技术是横在我们面前的拦路虎,我们如何解决他呢?
办法有2个:
1.跟踪并且分析代码然后自己补充完整。
2.用以壳解壳的办法。
对于一些stolen OEP code我们好象还可以接受(还不太多嘛),但是如果SDK把成段成段的抽调代码,那我估计你能把那些代码补全了还不如自己去去把这个程序写出来^-^。而我们知道这些被偷掉的代码全在壳里面,只不过他不属于程序的空间,所以我们不能把他dump下来。那么我们想:如果我们把他们全都dump下来以后,那不就不用自己去补了。在这种想法的促使下,以壳解壳的方法诞生了。
接下来的问题便是:我们怎么dump下来呢?
但是在这个问题的前面应该是dump什么部分?按照前面所说的,如果我们在dump下程序了以后运行发现程序在读某一块内存区域,但是那一块区域却什么都没有,这时你便应该知道要dump什么区域了吧!
那么如何dump呢?
使用LordPE的 dump region...(区域dump)功能就可以了,选种自己想要的区域就可以直接dump下来了!
在接下来是该如何装入原来的文件呢?
先给大概的出步骤:
1.使用PE Editor的Load section from disk...(从硬盘载入区段头)功能增加一个区域,放入壳代码;
2.修改那个新区段的RVA;3.重建PE文件(在重建选项一般保留“验正PE”就可以了)
对于1没什么好说的,我们来解释一下为什么要修改这个RVA。
代码在文件中有他们自己的位置,我们称为文件地址。而当他映射到内存的时候并不是像文件中的地址那样排列。他是按照RVA(相对虚拟地址)的地址+基址 来确定自己在内存中的位置的。所以我们要将原来壳代码所在的位置减掉基址添入就可以了。编辑使用edit section head....的功能。最后因为实际的PE文件和PE头里面的信息有写不一样(你都添加了一个区段当然不一样了),那么需要修复PE头,所以只选用验正PE,不建议在这个时候优化程序,因为我们一般的步骤是先添加区段壳代码,然后修复IAT,这个也是是要添加一个区段的哦!
----------------------------------------------------------------3.总结 现在我们来回答开始提出的三个问题:
1.什么是以壳解壳? 以壳解壳是针对主程序的部分代码被偷,进而提出来的一种解决办法。采用添加原壳代码的的手段,达到使程序运行时仍能像未脱壳以前那样正确的访问到壳代码空间。可以说是一种“懒”办法,但是对于某些程序被偷得太多的时候却是一种无奈之举!
2.什么时候要以壳解壳? 当你发现被偷掉的代码很多,自己不能手动补充完整的时候。
3.如何以壳解壳?
上面给出了一个以壳解壳的实例。下面也是一个(明天再帖^^)
4.以壳解壳有什么不足?
因为以壳解壳采用了壳中的代码,那么如果在壳中代码中有部分是校验,或者是一些检验脱壳的代码,那么我们无异于是引狼入室。而且保留了壳代码,不仅增加了文件大小而且留下了原程序本来就没有的东西,总让人心理不是很爽。所以我的向来主张是以壳解壳的办法是最后的救命稻草,不要太过于依赖。
5.什么时候不能使用以壳解壳的办法?
当壳代码的RVA小于基址的时候!上面的方法将不在适用。
例如:壳代码的RVA=300000 而程序的基址=400000。
那时我们怎么修改这个RVA呢?我还没有找到合适的办法,期待那位能告诉我 ^-^。
问题在这个帖子里面解决了:
【以壳脱壳 实例 ASProtect 1.23】
OD设置忽略除了内存访问之外的所有异常!
00401000 cry> 68 01009000 push crysb.00900001 //入口!
00401005 E8 01000000 call crysb.0040100B
0040100A C3 retn
0040100B C3 retn
0040100C EB 6E jmp short crysb.0040107C
0040100E C2 6873 retn 7368
Shift+F9走!第23次的时候第2次看到硬盘指纹。。。
016D46A5 3100 xor dword ptr ds:[eax],eax //第23次
016D46A7 EB 01 jmp short 016D46AA
016D46A9 68 648F0500 push 58F64
016D46AE 0000 add byte ptr ds:[eax],al
016D46B0 00EB add bl,ch
堆栈提示:
0012FF50 016C0000
0012FF54 016A0000
0012FF58 016D4138
0012FF5C 016E94E4 ASCII "6uob9ACQoUA="
0012FF60 016D3616 返回到 016D3616 来自 016C2524
0012FF64 016A0000
在CODE段下断,Shift+F9运行!
004085E0 8B4424 04 mov eax,dword ptr ss:[esp+4] //到这里!
004085E4 A3 98324C00 mov dword ptr ds:[4C3298],eax //[4C3298]是保存注册地址的
004085E9 C2 0400 retn 4
继续Shift+F9运行,第26次到达最后一次异常!
016D39EC 3100 xor dword ptr ds:[eax],eax //最后一次异常
016D39EE 64:8F05 0000000>pop dword ptr fs:[0]
016D39F5 58 pop eax
016D39F6 833D B07E6D01 0>cmp dword ptr ds:[16D7EB0],0
016D39FD 74 14 je short 016D3A13
016D39FF 6A 0C push 0C
016D3A01 B9 B07E6D01 mov ecx,16D7EB0
016D3A06 8D45 F8 lea eax,dword ptr ss:[ebp-8]
016D3A09 BA 04000000 mov edx,4
016D3A0E E8 2DD1FFFF call 016D0B40
016D3A13 FF75 FC push dword ptr ss:[ebp-4]
016D3A16 FF75 F8 push dword ptr ss:[ebp-8]
016D3A19 8B45 F4 mov eax,dword ptr ss:[ebp-C]
016D3A1C 8338 00 cmp dword ptr ds:[eax],0
016D3A1F 74 02 je short 016D3A23
016D3A21 FF30 push dword ptr ds:[eax]
016D3A23 FF75 F0 push dword ptr ss:[ebp-10]
016D3A26 FF75 EC push dword ptr ss:[ebp-14]
016D3A29 C3 retn //F2断下来,注意堆栈!
堆栈提示:
0012FF5C 016E7E9C
0012FF60 00400000 crysb.00400000
0012FF64 574F42C8
0012FF68 0012FFA4 =======>0012FF68
0012FF6C 016C0000
hr 0012FF68,F9运行!
016E8019 /EB 44 jmp short 016E805F //到这里,删除断点,F7一下!
016E801B |EB 01 jmp short 016E801E
016E801D |9A 51579CFC BF0>call far 00BF:FC9C5751
016E8024 |0000 add byte ptr ds:[eax],al
016E8026 |00B9 00000000 add byte ptr ds:[ecx],bh
016E802C |F3:AA rep stos byte ptr es:[edi]
016E805F 03C3 add eax,ebx //到这里,F8一下!
016E8061 BB C4000000 mov ebx,0C4 //这里就是我们以壳解壳的OEP=012E8061
016E8066 0BDB or ebx,ebx
016E8068 75 07 jnz short 016E8071
016E806A 894424 1C mov dword ptr ss:[esp+1C],eax
016E806E 61 popad
打开LordPE,完全DUMP这个进程!再区域脱壳Region00E50000-00E5C000.dmp(016E0000-00400000=012E0000)
(dump下来的区块必须包含以壳脱壳的OEP的低值范围)
组装Unpack.exe
按PE编辑器,导入dump.exe,按区段编辑,右键,导入dump下来的区段。这时候还需要编辑区段头OEP在这个区段里面,这个区块的基地址必须减去原来的40000,然后这个基地址就作为新的OEP基地址。参考Region00E50000-00E5C000.dmp看到新的基地址就是E50000-40000=E10000,改好之后保存,然后重建PE,选中dump PE。
请出AsprDbgr 修复输入表!
AsprDbgr v1.0beta (:P) Made by me... Manko.
iEP=401000 (C:\Program Files\CrystalButton2\crysb.exe)
IAT Start: 492000
End: 492730
Length: 730
IATentry 492208 = 16D1CD8 resolved as GetCommandLineA
IATentry 492224 = 16D1C64 resolved as GetModuleHandleA
IATentry 492244 = 16D17A4 resolved as GetProcAddress
IATentry 492288 = 16D1CC8 resolved as LockResource
IATentry 492298 = 16D1C8C resolved as GetVersion
IATentry 492320 = 16D1CB8 resolved as GetCurrentProcess
12 invalid entries erased.
Dip-Table at adress: 16D7AB4
0 4085E0 0 0 0 0 0 0 0 0 0 0 0 0
Last SEH passed. (16D39EE) Searching for signatures. Singlestepping to OEP!
Call + OEP-jump-setup at: 16E6049 ( Code: E8000000 5D81ED )
Mutated, stolen bytes at: 16E6095 ( Code: EB02CD20 EB02CD20 )
Erase of stolen bytes at: 16E5FF8 ( Code: 9CFCBF37 606E01B9 )
Repz ... found. Skipping erase of stolen bytes. ;)
possible (temp)OEP: 4364B6 (Reached from preOEP: 16E6009)
打开IR1.6,在OEP处添0364B6,获取输入表全部有效--再把OEP改成以壳脱壳的OEP--修复抓取文件!
呵呵~可以运行,,现在我们来Pre-Dip注册一下~~
OD载入Unpack_.exe
还记得4C3298?
DD 4C3298
004C3298 016C3861 Unpack_.016C3861
004C329C 6D6F6F7A
004C32A0 00000000
004C32A4 00007963
找块空地。。我找004DFFF4写入******
现在修改成
004C3298 004DFFF4 ASCII "******"
004C329C 6D6F6F7A
004C32A0 00000000
004C32A4 00007963
因为没有试用标志。。。就不用改了
现在复制可执行文本--覆盖保存!
运行看看。。。呵呵已经注册给******了。。
抓个图留恋吧。。。到此为止。。。
***********
这里演示如何跟踪 stolen code。
Stolen Code
push ebp
mov ebp,esp
push -1
push 49A4A8
push 4363B8
mov eax,dword ptr fs:[0]
push eax
mov dword ptr fs:[0],esp
sub esp,58
push ebx
push esi
push edi
mov dword ptr ss:[ebp-18],esp
55 8B EC 6A FF 68 A8 A4 49 00 68 B8 63 43 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58
53 56 57 89 65 E8
【UltraProtect 1.x -> RISCO Software Inc.】
【stolen code 的寻找】
【必须声明的是这个版本的壳有好几种保护方法,每种都需要不同的技巧。】
【完美卸载XP V9.14】
******************************************************************
Od设置不忽略INT3中断,其余异常全部忽略。隐藏!
OD载入
004AC000 N> 60 pushad //记下004AC000,这个后面要用到的!
004AC001 4E dec esi
004AC002 D3D6 rcl esi,cl
004AC004 4E dec esi
004AC005 66:D3E8 shr ax,cl
F9运行。
004BAB23 90 NOP //第一次也是最后一次INT3异常。
004BAB24 64:67:8F06 0000 POP DWORD PTR FS:[0]
004BAB2A 83C4 04 ADD ESP,4
004BAB2D 60 PUSHAD
004BAB2E E8 00000000 CALL NetClean.004BAB33
004BAB33 5E POP ESI
004BAB34 83EE 06 SUB ESI,6
004BAB37 B9 5B000000 MOV ECX,5B
004BAB3C 29CE SUB ESI,ECX
004BAB3E BA 09E5B87E MOV EDX,7EB8E509
004BAB43 C1E9 02 SHR ECX,2
004BAB46 83E9 02 SUB ECX,2
004BAB49 83F9 00 CMP ECX,0
004BAB4C 7C 1A JL SHORT NetClean.004BAB68
.................................................
堆栈内容
0012FF58 0012FFE0 指针到下一个 SEH 记录
0012FF5C 004BAAF0 SE 句柄 //右键对004BAAF0转存中跟随,下内存访问断点,Shift+F9!
0012FF60 F9E1E5CE
004BAAF0 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4] //下断点Shift+F9中断1
004BAAF4 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C]
004BAAF8 FF81 B8000000 INC DWORD PTR DS:[ECX+B8]
004BAAFE 8B00 MOV EAX,DWORD PTR DS:[EAX]
004BAB00 2D 03000080 SUB EAX,80000003
004BAB05 75 12 JNZ SHORT NetClean.004BAB19
004BAB07 90 NOP
004BAB08 90 NOP
004BAB09 90 NOP
004BAB0A 90 NOP
004BAB0B 33C0 XOR EAX,EAX
004BAB0D 8941 04 MOV DWORD PTR DS:[ECX+4],EAX
004BAB10 8941 08 MOV DWORD PTR DS:[ECX+8],EAX
004BAB13 8941 0C MOV DWORD PTR DS:[ECX+C],EAX
004BAB16 8941 10 MOV DWORD PTR DS:[ECX+10],EAX
004BAB19 C3 RETN
.................................................
004BAB4E 8B048E MOV EAX,DWORD PTR DS:[ESI+ECX*4] //下断点Shift+F9中断2,清除内存断点
004BAB51 8B5C8E 04 MOV EBX,DWORD PTR DS:[ESI+ECX*4+4]
004BAB55 03C3 ADD EAX,EBX
004BAB57 C1C8 0E ROR EAX,0E
004BAB5A 2BC2 SUB EAX,EDX
004BAB5C 81EA D41CF55C SUB EDX,5CF51CD4
004BAB62 89048E MOV DWORD PTR DS:[ESI+ECX*4],EAX
004BAB65 49 DEC ECX
004BAB66 ^ EB E1 JMP SHORT NetClean.004BAB49
004BAB68 61 POPAD
004BAB69 61 POPAD
004BAB6A C3 RETN //F4直接下来,这时是寻找Stolen Code时候了。
.................................................
再次点它的死穴。
命令行 d 12ffc0。
右键下硬件访问dword断点!
004C9B31 55 PUSH EBP //Stolen Code
004C9B32 8BEC MOV EBP,ESP //Stolen Code
004C9B34 6A FF PUSH -1 //Stolen Code
004C9B36 90 NOP
004C9B37 60 PUSHAD
004C9B38 60 PUSHAD
这个程序抽了5个字节。
........................................................................
ALT+M 打开内存镜像断点,对准它的第二个死穴点。
内存镜像, 项目 12
地址=00401000 //Code段下内存访问断点
大小=00047000 (290816.)
Owner=NetClean 00400000
区段=.text
Contains=code
类型=Imag 01001002
访问=R
初始访问=RWE
F9运行
004431F9 68 D8B24400 PUSH NetClean.0044B2D8 //临时Oep,滚动条向上看,如何判断抽掉多少字节,用滚动条是代码会混乱,右键分析代码,如我现在调整的样式,标签1
004431FE 68 B4334400 PUSH NetClean.004433B4 ; JMP to MSVCRT._except_handler3
00443203 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
00443209 50 PUSH EAX
0044320A 64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00443211 83EC 68 SUB ESP,68
00443214 53 PUSH EBX
00443215 56 PUSH ESI
00443216 57 PUSH EDI
.............................................................................
标签1
004431F4 8C DB 8C //真Oep
004431F5 . C3 RETN
004431F6 49 DB 49 ; CHAR 'I'
004431F7 2E DB 2E ; CHAR '.'
004431F8 79 DB 79 ; CHAR 'y'
004431F9 . 68 D8B24400 PUSH NetClean.0044B2D8
004431FE . 68 B4334400 PUSH NetClean.004433B4 ; JMP to MSVCRT._except_handler3; SE handler installation
00443203 . 64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00443209 . 50 PUSH EAX
0044320A . 64:8925 00000>MOV DWORD PTR FS:[0],ESP
00443211 . 83EC 68 SUB ESP,68
00443214 . 53 PUSH EBX
00443215 . 56 PUSH ESI
00443216 . 57 PUSH EDI
00443217 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
0044321A . 33DB XOR EBX,EBX
0044321C . 895D FC MOV DWORD PTR SS:[EBP-4],EBX
0044321F . 6A 02 PUSH 2
00443221 . FF15 70874400 CALL DWORD PTR DS:[448770] ; MSVCRT.__set_app_type
.............................................................................
还原代码!
55 8B EC 6A FF
004431F4 55 PUSH EBP //用Od插件修正入口为431F4直接脱壳吧,重建输入表的勾去掉
004431F5 8BEC MOV EBP,ESP
004431F7 6A FF PUSH -1
004431F9 . 68 D8B24400 PUSH NetClean.0044B2D8
004431FE . 68 B4334400 PUSH NetClean.004433B4 ; JMP to MSVCRT._except_handler3; SE handler installation
00443203 . 64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00443209 . 50 PUSH EAX
0044320A . 64:8925 00000>MOV DWORD PTR FS:[0],ESP
00443211 . 83EC 68 SUB ESP,68
00443214 . 53 PUSH EBX
00443215 . 56 PUSH ESI
00443216 . 57 PUSH EDI
00443217 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
0044321A . 33DB XOR EBX,EBX
0044321C . 895D FC MOV DWORD PTR SS:[EBP-4],EBX
0044321F . 6A 02 PUSH 2
00443221 . FF15 70874400 CALL DWORD PTR DS:[448770] ; MSVCRT.__set_app_type
........................................................................
修复IAT必须关闭OD单独开加壳程序修复,不然ImportREC停止响应,最后用ImportREC Oep填431F4,跟踪等级三轻松修复,有10个指针提示无法修复,你可以验证一下,经过验证全部是垃圾指针,通常ImportREC可全部修复指针,如有没有一般都是垃圾,拿剪刀全部Cut掉,修复后无法运行。
寻找出错原因。
004431C4 |. 68 00404500 PUSH 2_.00454000
004431C9 |. E8 DC000000 CALL <JMP.&msvcrt._initterm> //这个Call可能是新版Acprotect的解码技术,进这个Call里面,循环解码,没解完程序就崩溃。
004431CE |. 83C4 24 ADD ESP,24 //这里类似代码,我没有再次跟踪。
其实本版本Acprotect嵌有Oep处代码检验程序,发现Oep处代码被替换,立即拒绝解码,你失去了关键的代码当然程序无法运行,还要承认N次错误确定按钮。
004C9B31 55 PUSH EBP //Stolen Code
004C9B32 8BEC MOV EBP,ESP //Stolen Code
004C9B34 6A FF PUSH -1 //Stolen Code
我们已经掌握。
004431F9 . 68 D8B24400 PUSH NetClean.0044B2D8 //临时Oep也知道。
现在做什么,让程序认为你没有脱壳,将perplex段里面有用的内容全部解码。
方法
PUSH EBP //Stolen Code
MOV EBP,ESP //Stolen Code
PUSH -1 //Stolen Code
jmp 004431F9
Od载入脱壳修复后的程序,Ctrl+G 004AC000,右键清除分析。
004AC000 60 PUSHAD //4AC000是原来壳的入口点,将Oep入口代码复制到这里。
004AC001 4E DEC ESI
004AC002 D3D6 RCL ESI,CL
004AC004 4E DEC ESI
004AC005 66:D3E8 SHR AX,CL
004AC008 4E DEC ESI
004AC009 8BC3 MOV EAX,EBX
004AC00B 48 DEC EAX
004AC00C 7A 03 JPE SHORT Unpack_.004AC011
004AC00E 7B 01 JPO SHORT Unpack_.004AC011
004AC010 7A C1 JPE SHORT Unpack_.004ABFD3
004AC012 EF OUT DX,EAX ; I/O 命令
004AC013 F0:50 LOCK PUSH EAX ; 锁定前缀是不允许的
004AC015 E8 01000000 CALL Unpack_.004AC01B
.........................................................
55 8B EC 6A FF
jmp 004431F9
004AC000 55 push ebp
004AC001 8BEC mov ebp,esp
004AC003 6A FF push -1
004AC005 - E9 EF71F9FF jmp dump1_.004431F9
004AC00A C3 retn
004AC00B 48 dec eax
004AC00C 7A 03 jpe short dump1_.004AC011
004AC00E 7B 01 jpo short dump1_.004AC011
004AC010 7A C1 jpe short dump1_.004ABFD3
004AC012 EF out dx,eax
004AC013 F0:50 lock push eax ; 不允许锁定前缀
...........................................................
练过手的,常见壳脱壳步骤都做了记录(极大部分百度和一些视频教程),其中以壳脱壳的一些理论有点意思,逆向的学习要停一段时间了,最近人工智能什么的开始期末复习了,忙一下课内。这份东西待续吧。还是有很多壳的,每种壳又N多种anti,幸运的是大部分都有教程,通过模拟重现,再总结为什么这样做,比如为什么ESP定理有效,为什么最后一次异常法可以发挥作用,stolen code怎么跟踪,为什么两次内存断点可以发挥作用,这些东西里面都有提及,不光是模拟前人。估计不是对每个人有用,觉得有用的就扫一眼吧。
对应的练手的程序。
115 下载:http://115.com/file/c2ev3mxh#脱壳笔记.rar
【脱壳一般流程】
查壳(PEID、FI、PE-SCAN)--->寻找OEP(OD)--->脱壳/Dump(LordPE、PeDumper、OD自带的脱壳插件、PETools)--->修复(Import REConstructor)
【工具介绍】
1、查壳
PEID--功能强大的侦壳工具,自带脱壳插件(但是,效果不怎么样)
工作原理:核心是userdb.txt(大家看看就完全明白了)[通过壳的入口特征码进行辨认]
使用方法:可以拖放、也可以把PEID添加到右键菜单里面去
FI--功能强大的侦壳工具,DOS界面。
使用方法:可以拖放、可以使用DOS命令行
2、寻找OEP
ollydbg的四个区域
左上角是cpu窗口,分别是地址,机器码,汇编代码,注释;注释添加方便,而且还能即时显示函数的调用结果,返回值.
右上角是寄存器窗口,但不仅仅反映寄存器的状况,还有好多东东;双击即可改变Eflag的值,对于寄存器,指令执行后发生改变的寄存器会用红色突出显示.
cpu窗口下面还有一个小窗口,显示当前操作改变的寄存器状态.
左下角是内存窗口.可以ascii或者unicode两种方式显示内存信息.
右下角的是当前堆栈情况,还有注释啊.
几个经常使用的快捷键
F2:在需要的地方下断点(INT3型断点)
F3:选择打开程序
F4:运行到所选择的那一行
F7:单步进入
F8:单步跟踪
F9:执行程序(运行程序)
其中要特别讲一下3个F9的区别和作用:
根据Ollydbg.hlp的中文翻译
Shift+F9 - 与F9相同,但是如果被调试程序发生异常而中止,调试器会首先尝试执行被调试程序指定的异常处理(请参考忽略Kernel32中的内存非法访问)。
Ctrl+F9 - 执行直到返回,跟踪程序直到遇到返回,在此期间不进入子函数也不更新CPU数据。因为程序是一条一条命令执行的,所以速度可能会慢一些。按Esc键,可以停止跟踪。
Alt+F9 - 执行直到返回到用户代码段,跟踪程序直到指令所属于的模块不在系统目录中,在此期间不进入子函数也不更新CPU数据。因为程序是一条一条执行的,所以速度可能会慢一些。按Esc键,可以停止跟踪。
看这些中文介绍大家可能还不是很明白,用我们通俗的语句来说就是:
Ctrl+F9 运行至retn (一般到了retn之后接上F7返回)
Alt+F9 运行至上层调用的下句
Shift+F9 忽略异常运行
文件:
1.其中包括该菜单的下部有上次打开的纪录,该纪录保存有上次未清除的断点.
2.附加.对付那些Anti-Debug程序.先运行程序,再运行od,文件-->附加.
查看:
1.执行模块(Alt+E),查看程序使用的动态链接库
2.查看断点.Alt+B
调试:
1.运行(F9)加载程序后,运行!
2.暂停(F12)
3.单步进入(F7)遇见CALL进入!进入该子程序.
4.单步跳过(F8)遇见CALL不进去!
5.执行到返回(ALT+F9)就是执行到该子程的返回语句
查看-->文件
二进制文件编辑功能.查看-->文件,打开的文件是二进制显示.选中要改变的机器指令,空格,修改,右击-->保存.
具体的用途在后面的几壳脱壳课程当中将会用到,大家现在理解就行。在后面的操作中学会使用!
其他的一些具体的大家还是要看看OD的中文帮助的
3、Dump
OD自带的脱壳插件--到达OEP之后右键。。。
LordPE、PeDumper--选择所调试的进程--右键--完整脱壳
4、修复
Import REConstructor 1.6
【壳的介绍】
壳出于程序作者想对程序资源压缩、注册保护的目的,把壳分为压缩壳和加密壳两种
UPX ASPCAK TELOCK PELITE NSPACK ...
ARMADILLO ASPROTECT ACPROTECT EPE SVKP ...
顾名思义,压缩壳只是为了减小程序体积对资源进行压缩,加密壳是程序输入表等等进行加密保护。当然加密壳的保护能力要强得多!
【常见的脱壳方法】
预备知识
1.PUSHAD (压栈) 代表程序的入口点,
2.POPAD (出栈) 代表程序的出口点,与PUSHAD想对应,一般找到这个OEP就在附近
3.OEP:程序的入口点,软件加壳就是隐藏了OEP(或者用了假的OEP/FOEP),只要我们找到程序真正的OEP,就可以立刻脱壳。
方法一:单步跟踪法
1.用OD载入,点“不分析代码!”
2.单步向下跟踪F8,实现向下的跳。也就是说向上的跳不让其实现!(通过F4)
3.遇到程序往回跳的(包括循环),我们在下一句代码处按F4(或者右健单击代码,选择断点——>运行到所选)
4.绿色线条表示跳转没实现,不用理会,红色线条表示跳转已经实现!
5.如果刚载入程序,在附近就有一个CALL的,我们就F7跟进去,不然程序很容易跑飞,这样很快就能到程序的OEP
6.在跟踪的时候,如果运行到某个CALL程序就运行的,就在这个CALL中F7进入
7.一般有很大的跳转(大跨段),比如 jmp XXXXXX 或者 JE XXXXXX 或者有RETN的一般很快就会到程序的OEP。
Btw:在有些壳无法向下跟踪的时候,我们可以在附近找到没有实现的大跳转,右键-->“跟随”,然后F2下断,Shift+F9运行停在“跟随”的位置,再取消断点,继续F8单步跟踪。一般情况下可以轻松到达OEP!
方法二:ESP定律法
ESP定理脱壳(ESP在OD的寄存器中,我们只要在命令行下ESP的硬件访问断点,就会一下来到程序的OEP了!)
1.开始就点F8,注意观察OD右上角的寄存器中ESP有没突现(变成红色)。(这只是一般情况下,更确切的说我们选择的ESP值是关键句之后的第一个ESP值)
2.在命令行下:dd XXXXXXXX(指在当前代码中的ESP地址,或者是hr XXXXXXXX),按回车!
3.选中下断的地址,断点--->硬件访--->WORD断点。
4.按一下F9运行程序,直接来到了跳转处,按下F8,到达程序OEP。
方法三:内存镜像法
1:用OD打开软件!
2:点击选项——调试选项——异常,把里面的忽略全部√上!CTRL+F2重载下程序!
3:按ALT+M,打开内存镜象,找到程序的第一个.rsrc.按F2下断点,然后按SHIFT+F9运行到断点,接着再按ALT+M,打开内存镜象,找到程序的第一个.rsrc.上面的.CODE(也就是00401000处),按F2下断点!然后按SHIFT+F9(或者是在没异常情况下按F9),直接到达程序OEP!
注:.rsrc是资源,一般壳都对资源进行操作,所以上面的
方法四:一步到达OEP
1.开始按Ctrl+F,输入:popad(只适合少数壳,包括UPX,ASPACK壳),然后按下F2,F9运行到此处
2.来到大跳转处,点下F8,到达OEP!
这个定理是最有效的
方法五:最后一次异常法
1:用OD打开软件
2:点击选项——调试选项——异常,把里面的√全部去掉!CTRL+F2重载下程序
3:一开始程序就是一个跳转,在这里我们按SHIFT+F9,直到程序运行,记下从开始按SHIFT+F9到程序运行的次数m!
4:CTRL+F2重载程序,按SHIFT+F9(这次按的次数为程序运行的次数m-1次)
5:在OD的右下角我们看见有一个"SE 句柄",这时我们按CTRL+G,输入SE 句柄前的地址!
6:按F2下断点!然后按SHIFT+F9来到断点处!
7:去掉断点,按F8慢慢向下走!
8:到达程序的OEP!
方法六:模拟跟踪法
1:先试运行,跟踪一下程序,看有没有SEH暗桩之类
2:ALT+M打开内存镜像,找到(包含=SFX,imports,relocations)
内存镜像,项目 30
地址=0054B000
大小=00002000 (8192.)
Owner=check 00400000
区段=.aspack
包含=SFX,imports,relocations
类型=Imag 01001002
访问=R
初始访问=RWE
3:地址为0054B000,如是我们在命令行输入tc eip<0054B000,回车,正在跟踪ing。。
Btw:大家在使用这个方法的时候,要理解他是要在怎么样的情况下才可以使用
方法七:“SFX”法
1:设置OD,忽略所有异常,也就是说异常选项卡里面都打上勾
2:切换到SFX选项卡,选择“字节模式跟踪实际入口(速度非常慢)”,确定。
3:重载程序(如果跳出是否“压缩代码?”选择“否”,OD直接到达OEP)
Btw:这种方法不要滥用得好,锻炼能力为妙。
【UXP练手】【附件 upx.exe】
---------------------------------------------------------------------------------
黑鹰红客基地动画教程
黑鹰红客基地www.3800cc.com
专业的红客安全技术培训基地
多抽出一分钟时间学习.让你的生命更加精彩.
注:10元的动画免费对外公布.20.50.100.200元的动画只提供给本站的vip会员做为辅助教材.
---------------------------------------------------------------------------------
手脱UPX的四种方法
首先,查壳,使用PEID是UPX 0.89.6 - 1.02 / 1.05 - 1.24 -> Markus & Laszlo,使用FI为UPX v1.08
接下来用OD载入,提示为“压缩代码是否继续分析”,我们选择否
我在这里介绍几种方法,请看我的操作。
方法1:单步跟踪(最常见的方法)
0040E8C0 N> 60 pushad //停在这里了,我们F8单步
0040E8C1 BE 15B04000 mov esi,NOTEPAD.0040B015
0040E8C6 8DBE EB5FFFFF lea edi,dword ptr ds:[esi+FFFF>
0040E8CC 57 push edi
0040E8CD 83CD FF or ebp,FFFFFFFF
0040E8D0 EB 10 jmp short NOTEPAD.0040E8E2 //跳
》》》》
0040E8E2 8B1E mov ebx,dword ptr ds:[esi] //跳到这里
0040E8E4 83EE FC sub esi,-4
0040E8E7 11DB adc ebx,ebx
0040E8E9 ^ 72 ED jb short NOTEPAD.0040E8D8 //这里要往回跳了
0040E8EB B8 01000000 mov eax,1 //F4,然后继续F8
0040E8F0 01DB add ebx,ebx
0040E8F2 75 07 jnz short NOTEPAD.0040E8FB //跳
》》》》
0040E8FB 11C0 adc eax,eax //来到这里,F8继续
0040E8FD 01DB add ebx,ebx
0040E8FD 01DB add ebx,ebx
0040E8FF ^ 73 EF jnb short NOTEPAD.0040E8F0
0040E901 75 09 jnz short NOTEPAD.0040E90C //跳
》》》》
0040E90C 31C9 xor ecx,ecx //跳到这里,继续F8
0040E90E 83E8 03 sub eax,3
0040E90E 83E8 03 sub eax,3
0040E911 72 0D jb short NOTEPAD.0040E920 //跳
》》》》
0040E920 01DB add ebx,ebx //跳到这里,继续F8
0040E922 75 07 jnz short NOTEPAD.0040E92B //跳
》》》
0040E92B 11C9 adc ecx,ecx //跳到了这里,继续F8
0040E92D 01DB add ebx,ebx
0040E92F 75 07 jnz short NOTEPAD.0040E938 //跳
》》》
0040E938 11C9 adc ecx,ecx //跳到这里,继续F8
0040E93A 75 20 jnz short NOTEPAD.0040E95C //跳
》》》》
0040E95C 81FD 00F3FFFF cmp ebp,-0D00 //来到这,继续F8
0040E962 83D1 01 adc ecx,1
0040E965 8D142F lea edx,dword ptr ds:[edi+ebp]
0040E968 83FD FC cmp ebp,-4
0040E96B 76 0F jbe short NOTEPAD.0040E97C
0040E96D 8A02 mov al,byte ptr ds:[edx]
0040E96F 42 inc edx
0040E970 8807 mov byte ptr ds:[edi],al
0040E972 47 inc edi
0040E973 49 dec ecx
0040E974 ^ 75 F7 jnz short NOTEPAD.0040E96D //要往回跳了
0040E976 ^ E9 63FFFFFF jmp NOTEPAD.0040E8DE
0040E97B 90 nop
0040E97C 8B02 mov eax,dword ptr ds:[edx]// F4,继续F8
0040E97E 83C2 04 add edx,4
0040E981 8907 mov dword ptr ds:[edi],eax
0040E983 83C7 04 add edi,4
0040E986 83E9 04 sub ecx,4
0040E989 ^ 77 F1 ja short NOTEPAD.0040E97C
0040E98B 01CF add edi,ecx
0040E98D ^ E9 4CFFFFFF jmp NOTEPAD.0040E8DE //要往回跳了。
0040E992 5E pop esi //这里F4,继续F8
0040E993 89F7 mov edi,esi
0040E995 B9 DD000000 mov ecx,0DD
0040E99A 8A07 mov al,byte ptr ds:[edi]
0040E99C 47 inc edi
0040E99D 2C E8 sub al,0E8
0040E99F 3C 01 cmp al,1
0040E9A1 ^ 77 F7 ja short NOTEPAD.0040E99A //要往回跳了
0040E9A3 803F 00 cmp byte ptr ds:[edi],0 //这里F4,继续F8
0040E9A6 ^ 75 F2 jnz short NOTEPAD.0040E99A //要往回跳了
0040E9A8 8B07 mov eax,dword ptr ds:[edi] // F4,继续F8
0040E9AA 8A5F 04 mov bl,byte ptr ds:[edi+4]
0040E9AD 66:C1E8 08 shr ax,8
0040E9B1 C1C0 10 rol eax,10
0040E9B4 86C4 xchg ah,al
0040E9B6 29F8 sub eax,edi
0040E9B8 80EB E8 sub bl,0E8
0040E9BB 01F0 add eax,esi
0040E9BD 8907 mov dword ptr ds:[edi],eax
0040E9BF 83C7 05 add edi,5
0040E9C2 89D8 mov eax,ebx
0040E9C4 ^ E2 D9 loopd short NOTEPAD.0040E99F //要往回跳了
0040E9C6 8DBE 00C00000 lea edi,dword ptr ds:[esi+C000> //F4继续F8
0040E9CC 8B07 mov eax,dword ptr ds:[edi]
0040E9CE 09C0 or eax,eax
0040E9D0 74 3C je short NOTEPAD.0040EA0E
0040E9D2 8B5F 04 mov ebx,dword ptr ds:[edi+4]
0040E9D5 8D8430 14EC00>lea eax,dword ptr ds:[eax+esi+>
0040E9DC 01F3 add ebx,esi
0040E9DE 50 push eax
0040E9DF 83C7 08 add edi,8
0040E9E2 FF96 A0EC0000 call dword ptr ds:[esi+ECA0]
0040E9E8 95 xchg eax,ebp
0040E9E9 8A07 mov al,byte ptr ds:[edi]
0040E9EB 47 inc edi
0040E9EC 08C0 or al,al
0040E9EE ^ 74 DC je short NOTEPAD.0040E9CC
0040E9F0 89F9 mov ecx,edi
0040E9F2 57 push edi
0040E9F3 48 dec eax
0040E9F4 F2:AE repne scas byte ptr es:[edi]
0040E9F6 55 push ebp
0040E9F7 FF96 A4EC0000 call dword ptr ds:[esi+ECA4]
0040E9FD 09C0 or eax,eax
0040E9FF 74 07 je short NOTEPAD.0040EA08
0040EA01 8903 mov dword ptr ds:[ebx],eax
0040EA03 83C3 04 add ebx,4
0040EA06 ^ EB E1 jmp short NOTEPAD.0040E9E9 //要往回跳了
0040EA08 FF96 A8EC0000 call dword ptr ds:[esi+ECA8]
0040EA0E 61 popad //这里F4,继续F8
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC //在这里直接跳到了OEP
》》》》
004010CC 55 push ebp //来到这里,在此dump
004010CD 8BEC mov ebp,esp
004010CF 83EC 44 sub esp,44
其他操作请看动画
方法2:ESP定律手动脱壳
0040E8C0 N> 60 pushad //停在这里了,我们F8单步
0040E8C1 BE 15B04000 mov esi,NOTEPAD.0040B015 //ESP突现,0012FFA4
dd 0012FFA4回车, 断点--硬件访问--WORD,F9运行,直接来到这里
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC //来到这单步就到了OEP
不详述,和方法一一样了
方法3:内存镜像法
(由于经过了方法2和方法3大家都熟悉了代码,我在这里就不写了)
ALT+M打开内存
找到.rsrc,F2下断,F9运行
。。。。。。
ALT+M打开内存
找到UPX0,F2下断,F9运行
0040EA01 8903 mov dword ptr ds:[ebx],eax//来到这,F8继续
0040EA03 83C3 04 add ebx,4
0040EA06 ^ EB E1 jmp short NOTEPAD.0040E9E9
0040EA08 FF96 A8EC0000 call dword ptr ds:[esi+ECA8]
0040EA0E 61 popad
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC
其他的就不说了~请看动画。
方法4:捷径
直接CTRL+F,输入popad
0040EA0E 61 popad//F2下断,F9运行,F2取消断点,单步F8
0040EA0F - E9 B826FFFF jmp NOTEPAD.004010CC
---------------------------------------------------------------------------------
【aspack脱壳练手】
【AsPack-KillBox.exe】
【AsPack-登陆器.exe】
“KillBox”用PEID查得是ASPack 2.12 -> Alexey Solodovnikov
1、单步跟踪法
2、ESP定律法
00424001 K> 60 pushad //入口,看到关键提示大家就应该惊醒了,单步F8
00424002 E8 03000000 call KillBox.0042400A //到这里,注意寄存器提示ESP=0012FFA4
00424007 - E9 EB045D45 jmp 459F44F7
0042400C 55 push ebp
0042400D C3 retn
命令行下断hr 0012FFA4,F9运行!
3、内存镜像法
首先Alt+M打开内存镜像
找到.rsrc区段
内存映射,项目 29
地址=004D3000
大小=00241000 (2363392.)
宿主=登陆器 00400000
区段=.rsrc //F2下断,Shift+F9运行!
包含=resources
类型=Imag 01001002
访问=R
初始访问=RWE
继续
内存映射,项目 22
地址=00401000
大小=000BB000 (765952.)
宿主=登陆器 00400000
区段=CODE //F2下断,Shift+F9运行!直接到达OEP!
包含=code
类型=Imag 01001002
访问=R
初始访问=RWE
********************************************************************************************
"登陆器"其实是一个ASPack的变形壳
今天我们使用2种方法快速搞定它!
一、ESP定律法
二、内存断点法
******************************************************************************************************
一、ESP定律法
OD载入程序
00717082 登陆> 60 pushad //入口,看到关键提示大家就应该惊醒了,单步F8
00717083 E8 00000000 call 登陆器.00717088 //到这里,注意寄存器提示ESP=0012FFA4
00717088 5D pop ebp
00717089 81ED B6A4450>sub ebp,登陆器.0045A4B6
0071708F 8DBD B0A4450>lea edi,dword ptr ss:[ebp+45A4B0]
00717095 81EF 8200000>sub edi,82
命令行下断hr 0012FFA4,F9运行!
00717374 - FFE0 jmp eax ; 登陆器.00714001 //到这里,单步F8
00717376 42 inc edx
00717377 4B dec ebx
00717378 2E:44 inc esp
0071737A 41 inc ecx
00714001 60 pushad //来到这里,仍然是关键提示,单步F8
00714002 E8 03000000 call 登陆器.0071400A //到这里,ESP=0012FFA4(和上面的一样),由于上一个硬件断点没删除所以到这里我们直接F9就可以了!
00714007 - E9 EB045D45 jmp 45CE44F7
0071400C 55 push ebp
0071400D C3 retn
007143B0 /75 08 jnz short 登陆器.007143BA //到这里!删除断点,F8
007143B2 |B8 01000000 mov eax,1
007143B7 |C2 0C00 retn 0C
007143BA \68 D8BD4B00 push 登陆器.004BBDD8
007143BF C3 retn //返回到 004BBDD8 (登陆器.004BBDD8),程序的OEP!
004BBDD8 55 push ebp //OEP,看入口代码特征就知道程序是Delphi写的
004BBDD9 8BEC mov ebp,esp
004BBDDB 83C4 F0 add esp,-10
004BBDDE B8 98B94B00 mov eax,登陆器.004BB998
004BBDE3 E8 BCA5F4FF call 登陆器.004063A4
004BBDE8 A1 7CE84B00 mov eax,dword ptr ds:[4BE87C]
004BBDED 8B00 mov eax,dword ptr ds:[eax]
004BBDEF E8 1073FAFF call 登陆器.00463104
在此LordPE完全Dump!请出Import来修复下!OEP处填BBDD8--自动搜索IAT--获取输入表(全部有效)--FixDump!
测试正常运行,用PEID查看是Borland Delphi 6.0 - 7.0写的
好了,ESP定律法就到这里,下面介绍的是内存断点法
******************************************************************************************************
二、内存断点法
重新载入下吧,来实行我们的内存断点法
首先Alt+M打开内存镜像
找到.rsrc区段
内存映射,项目 29
地址=004D3000
大小=00241000 (2363392.)
宿主=登陆器 00400000
区段=.rsrc //F2下断,Shift+F9运行!
包含=resources
类型=Imag 01001002
访问=R
初始访问=RWE
77F764F3 66:8B50 0C mov dx,word ptr ds:[eax+C] //来到这里,我们不用管它
77F764F7 8995 6CFFFFF>mov dword ptr ss:[ebp-94],edx
77F764FD 8D70 10 lea esi,dword ptr ds:[eax+10]
77F76500 89B5 68FFFFF>mov dword ptr ss:[ebp-98],esi
77F76506 66:F747 02 F>test word ptr ds:[edi+2],0FFFF
再次Alt+M打开内存镜像
找到.code区段或者是.text区段(因为编写语言不一样所以区段名称的一样的,一般是00401000段)
内存映射,项目 22
地址=00401000
大小=000BB000 (765952.)
宿主=登陆器 00400000
区段=CODE //F2下断,Shift+F9运行!直接到达OEP!
包含=code
类型=Imag 01001002
访问=R
初始访问=RWE
004BBDD8 55 push ebp //OEP,看入口代码特征就知道程序是Delphi写的
004BBDD9 8BEC mov ebp,esp
004BBDDB 83C4 F0 add esp,-10
004BBDDE B8 98B94B00 mov eax,登陆器.004BB998
004BBDE3 E8 BCA5F4FF call 登陆器.004063A4
004BBDE8 A1 7CE84B00 mov eax,dword ptr ds:[4BE87C]
在此LordPE完全Dump!请出Import来修复下!OEP处填BBDD8--自动搜索IAT--获取输入表(全部有效)--FixDump!
测试正常运行,用PEID查看是Borland Delphi 6.0 - 7.0写的
【fsg 脱壳练手】
【fsg 1.33.exe】
【FSG 1.33变形壳.exe】
【FSG 2.0】
【fsg 1.33.exe】
方法一:单步法(忽略所有异常)
方法二:ESP定律(忽略所有异常)
这里没有明显的pushad指令,但是还是满足ESP定理的,单步如下
004103ED 56 push esi
004103EE 96 xchg eax,esi ; fsg_1_33.004001B0
004103EF B2 80 mov dl,0x80
004103F1 A4 movs byte ptr es:[edi],byte ptr ds:[esi]
在xchg eax,esi 处,发现esp寄存器发生变化,这是通过代码变形,使得不用直接使用pushad。
对 00112FFC0对应的数据下硬件断点,运行到达这里
0041045A AD lods dword ptr ds:[esi]
0041045B 48 dec eax
0041045C 74 0A je Xfsg_1_33.00410468
0041045E 79 02 jns Xfsg_1_33.00410462
00410460 AD lods dword ptr ds:[esi]
这里撤销硬件断点,单步,很快就可以到OEP了
00410480 /EB 09 jmp Xfsg_1_33.0041048B
00410482 |FE0E dec byte ptr ds:[esi]
00410484 -|0F84 420CFFFF je fsg_1_33.004010CC
0041048A |56 push esi
0041048B \55 push ebp
这里的判断ds:[esi]里面的值,如果等于0,就跳装到4010CC,这个就是OEP了,这是这个壳的一个特点,熟悉一下就行。
(dump的时候断点要取出,不然断点出dump下来的是int 3)
方法三:模拟跟踪法(不忽略内存异常)[首先忽略所有异常,F9试运行一下,遇到异常,好我们现在试下不忽略内存异常,(这是一个自己尝试的过程目的就是是要找到好多调试设置!),再试运行,OK,程序运行了。。要的就是他,模拟跟踪法是需要在没有异常的情况下才能够完全运用的]
ALT+M,打开内存镜像,
内存镜像,项目 15
地址=0040C000
大小=00005000 (20480.)
Owner=fsg_1_33 00400000
区段=
包含=SFX,imports,resources
类型=Imag 01001002
访问=R
初始访问=RWE
下命令行tc eip<0040c000,enter。正在跟踪之中。。。。有时候需要点时间等~
【FSG 1.33变形壳.exe】
单步几步,ESP=0012FFC0的时候,跟随到数据窗口中,下硬件访问断点,在来到的地方单步到这里
这段循环跟踪一下,就知道是处理IAT表的00430801 /EB 09 jmp short 0043080C这句一直得不到运行,直接下断点让其运行,在单步几步,就运行到这里了
00402666 55 push ebp ; COMCTL32.#241
00402667 8BEC mov ebp, esp
00402669 6A FF push -1
0040266B 68 00674100 push 00416700
00402670 68 FC504000 push 004050FC
00402675 64:A1 00000000 mov eax, dword ptr fs:[0]
0040267B 50 push eax
0040267C 64:8925 0000000>mov dword ptr fs:[0], esp
00402683 83EC 58 sub esp, 58
00402686 53 push ebx
00402687 56 push esi
00402688 57 push edi
00402689 8965 E8 mov dword ptr [ebp-18], esp
0040268C FF15 14524100 call dword ptr [415214] ; kernel32.GetVersion
很明显的VC入口特征。这里就是OEP了
修复的时候发现有个指针是无效的,我们就剪切掉吧。
这时候还是不可以运行。重新用od导入修复后的文件,发现有一个int 异常,直接nop掉
0040127E 90 nop
0040127F 90 nop
00401280 |> 8D4D E4 lea ecx, dword ptr [ebp-1C]
然后就可以运行了。
【FSG 2.0.exe】
直接用ESP定理,在入口出单步几步,直到
0040015D A4 movs byte ptr es:[edi], byte ptr [esi]
对esp跟踪到数据里面,对对应的数据设置内存断点。
004001C2 AD lods dword ptr [esi]
004001C3 97 xchg eax, edi
004001C4 AD lods dword ptr [esi]
到达这里之后,先删除断点 ,跟踪几步就到了。
在这个图里面,可以看到jmp dword ptr[ebx+C]一直没有被执行,对其F2,然后F9
可以看到ds:[004133A4]=00401000 (fsg_2_0.00401000),401000刚好是代码段附近的,这里就是OEP了,跟随进去。
00401000 2BDB sub ebx, ebx ; fsg_2_0.00413398
00401002 B8 4CA04000 mov eax, 0040A04C
00401007 C700 08000000 mov dword ptr [eax], 8
0040100D C740 04 FF00000>mov dword ptr [eax+4], 0FF
这时候用Import REC是无效的,fsg2.0对输入表加密了(或者有hook)
00401015 E8 DC620000 call 004072F6 ; jmp 到 COMCTL32.InitCommonControlsEx
看这一句,跟随进去,马上看到HOOK表了
0040723C - FF25 54904000 jmp dword ptr [409054] ; kernel32.CreateFileMappingA
00407242 - FF25 50904000 jmp dword ptr [409050] ; kernel32.CreateThread
……………………………..
004072F0 - FF25 08904000 jmp dword ptr [409008] ; GDI32.GetObjectA
004072F6 - FF25 00904000 jmp dword ptr [409000] ; COMCTL32.InitCommonControlsEx
跟随进入数据窗口,执行命令d 409060,进入数据窗口,上下翻动,可以看到转存的IAT表
00409000 77184088 園w COMCTL32.InitCommonControlsEx
…………………………………………………………………………
0040908C 77D24A4E NJ襴 USER32.EndDialog
00409090 7FFFFFFF
00409094 7632309F ?2v comdlg32.GetOpenFileNameA
00409098 7FFFFFFF
计算一下便宜,填进去就可以了,IAT RVA=9000,size=98
把无效指针剪切出来就行了
【PECompact 】
【PECompact 1.84.exe】一个ESP定理搞定
【PECompact 2.55.EXE】
这个壳一开始就给你弄了个SHE异常
FS寄存器指向当前活动线程的TEB结构(线程结构)偏移 说明000 指向SEH链指针004 线程堆栈顶部008 线程堆栈底部00C SubSystemTib010 FiberData014 ArbitraryUserPointer018 FS段寄存器在内存中的镜像地址020 进程PID024 线程ID02C 指向线程局部存储指针030 PEB结构地址(进程结构)034 上个错误号
参考< http://bbs.pediy.com/archive/index.php?t-100224.html>
所以这里ESP不好用了。
这里用了前人一个套路(最不喜欢套路了,没自己弄明白)
设置Ollydbg忽略所有的异常选项。
od载入
01001000 N> B8 90BA0101 mov eax,NOTEPAD.0101BA90
01001005 50 push eax ; NOTEPAD.0101BA90
01001006 64:FF35 0000000>push dword ptr fs:[0]
0100100D 64:8925 0000000>mov dword ptr fs:[0],esp
01001014 33C0 xor eax,eax
01001016 8908 mov dword ptr ds:[eax],ecx
01001018 50 push eax
下断点:BP VirtualFree。中断后,取消断点,Alt+F9。
002F00C0 58 pop eax //返回到这
002F00C1 EB 03 jmp short 002F00C6
002F00C3 33C0 xor eax,eax
002F00C5 48 dec eax
002F00C6 5D pop ebp
002F00C7 5B pop ebx
然后,ctrl+F ,查找 push 8000(特征码)。
002F093E 03C7 add eax,edi
002F0940 68 00800000 push 8000 //这里
002F0945 6A 00 push 0
002F0947 FFB5 951C0010 push dword ptr ss:[ebp+10001C95]
002F094D FF10 call dword ptr ds:[eax]
002F094F 8B46 0C mov eax,dword ptr ds:[esi+C]
002F0952 03C7 add eax,edi
002F0954 5D pop ebp
002F0955 5E pop esi
002F0956 5F pop edi
002F0957 5B pop ebx
002F0958 C3 retn //此处f2 ,下断
F9 ,运行,此时断了。单步f8,来到
0101BB3D 8985 C8120010 mov dword ptr ss:[ebp+100012C8],eax ; NOTEPAD.0100739D
0101BB43 8BF0 mov esi,eax
0101BB45 59 pop ecx
0101BB46 5A pop edx
0101BB47 EB 0C jmp short NOTEPAD.0101BB55
0101BB49 03CA add ecx,edx
0101BB4B 68 00800000 push 8000
0101BB50 6A 00 push 0
0101BB52 57 push edi
0101BB53 FF11 call dword ptr ds:[ecx]
0101BB55 8BC6 mov eax,esi
0101BB57 5A pop edx
0101BB58 5E pop esi
0101BB59 5F pop edi
0101BB5A 59 pop ecx
0101BB5B 5B pop ebx
0101BB5C 5D pop ebp
0101BB5D FFE0 jmp eax //跳到oep
0101BB5F 0000 add byte ptr ds:[eax],al
0101BB61 0000 add byte ptr ds:[eax],al
0100739D 6A 70 push 70 //OEP
0100739F 68 98180001 push PECompac.01001898
010073A4 E8 BF010000 call PECompac.01007568
010073A9 33DB xor ebx,ebx
010073AB 53 push ebx
010073AC 8B3D CC100001 mov edi,dword ptr ds:[10010CC] ; kernel32.GetModuleHandleA
010073B2 FFD7 call edi
010073B4 66:8138 4D5A cmp word ptr ds:[eax],5A4D
010073B9 75 1F jnz short PECompac.010073DA
下面就是DUMP进程,ImportREC修复输入表了。
【北斗 nspack】
【北斗1.4.exe】ESP定理直接搞定
【北斗 3.4.exe】ESP定理直接搞定
【PEncrypt 4.0】
【PEncrypt V4.0.EXE】最后一次异常法
这是一个比较少见的可,最后一次异常发搞定他
两次shift + F9,到这里
0040CCD2 4B dec ebx
0040CCD3 6F outs dx,dword ptr es:[edi]
0040CCD4 6368 69 arpl word ptr ds:[eax+69],bp
0040CCD7 8B4424 04 mov eax,dword ptr ss:[esp+4]
0040CCDB 8B00 mov eax,dword ptr ds:[eax]
这时候看堆栈
在SE句柄上面下断点40CCD7,再次shift+F9,这时候继续单步,很快就到OEP了。
用LoadPE脱壳,然后Import REC修复,这时候还是不可以运行,重新启动LoadPE,设置如下:
然后修复一下,就可以运行了。
这是一个比较陌生的壳,要多种方法不断尝试,特别是SHE是特别麻烦的事。
【SFX 方法脱壳】
直接设置这里,可以对80%压缩壳起作用,部分加密壳也可以,不过对于acprotect ,asprotect等强壳无效
【yoda's cryptor 1.2脱壳】
【Yoda's Crypter v1.2.98.E.exe】ESP无效了,两次内存断点可以搞定,先对资源段下断点,然后对代码段下断点,就可以到达OEP,IAT修复需要用Import REC的等级修复。
如图:
<注:尽量使用没有太多插件的od,不然有时候od会出现一些异常,如果用跟踪等级3,可以每次只选几个,反复进行,就不会死机了>
【tElock 脱壳】
【tElock.exe】
第一种方法:最后一次异常法
最后一次异常法,一共有21次异常(不断shift+F9)知道运行起来,重新载入od,20次忽略异常,就可以到最后一次异常处
看堆栈里面的内容,到0040D7FB出下断点,shift+F9,运行到这里,所有的SHE都跳过了,然后就一直单步,如果有pushad或者popad这两个指令,特别关注一下,很快就可以到OEP。
一直运行到这里,跟随,到达OEP
0040D7AF 61 popad
0040D7B0 - FF6424 D0 jmp dword ptr [esp-30] ; tElock.004010CC
接着就是修复IAT了,tElock的IAT是比较恶心的,记得很多人说过Import REC在用lever 3的时候会死机,其实这个和od有关,这时候如果直接打开一个新的tElock.exe,然后Import REC载入的进程不要和OD公用一个,这个问题集就不存在了,如果还是会死,那么就几个几个修复,最后有四个无效的,直接剪切掉就行了。
【PETITE脱壳】
【PETITE.98.E.exe】
这个壳可以用ESP定理,但是这里有点不一样
pushfw
pushad
对应
popad
pushfw
运行到这里pushad的就结束了,查看ESP,下内存断点。搞定
【PEtite 2.x.exe】同上ESP定理搞定。
【ESP定律 OR 两次内存断点 配合寻找OEP】
一.准备知识
在我们开始讨论ESP定律之前,我先给你讲解一下一些简单的汇编知识。
1.call
这个命令是访问子程序的一个汇编基本指令。也许你说,这个我早就知道了!别急请继续看完。call真正的意义是什么呢?我们可以这样来理解:
1.向堆栈中压入下一行程序的地址;
2.JMP到call的子程序地址处。
例如:
00401029.E8 DA240A00 call 004A3508
0040102E.5A pop edx
在执行了00401029以后,程序会将0040102E压入堆栈,然后JMP到004A3508地址处!
也就是压入下一个EIP的值
2.RETN
与call对应的就是RETN了。对于RETN我们可以这样来理解:
1.将当前的ESP中指向的地址出栈;
2.JMP到这个地址。
这个就完成了一次调用子程序的过程。在这里关键的地方是:如果我们要返回父程序,则当我们在堆栈中进行堆栈的操作的时候,一定要保证在RETN这条指令之前,ESP指向的是我们压入栈中的地址。这也就是著名的“堆栈平衡”原理!
3.狭义ESP定律
ESP定律的原理就是“堆栈平衡”原理。
让我们来到程序的入口处看看吧!
1.这个是加了ASPACK壳的入口时各个寄存器的值!
EAX 00000000
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 0040D000 ASPACK.<ModuleEntryPoint>
2.这个是ASPACK壳JMP到OEP后的寄存器的值!
EAX 004010CC ASPACK.004010CC
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 004010CC ASPACK.004010CC
呵呵~是不是除了EIP不同以外,eax保存当前OEP值,其他都一模一样啊!
为什么会这样呢?我们来看看
0040D000 A> 60 pushad //注意这里ESP=0012FFC4
0040D001 E8 00000000 call ASPACK.0040D006 //ESP=0012FFA4
PUSHAD就是把所有寄存器压栈!我们在到壳的最后看看:
0040D558 61 popad //ESP=0012FFA4
0040D559 75 08 jnz short ASPACK.0040D563 //注意这里ESP=0012FFC4
也就是说当我们对ESP的0012FFA4下硬件访问断点之后。当程序要通过堆栈访问这些值
,从而恢复原来寄存器的值,准备跳向苦苦寻觅的OEP的时候,OD帮助我们中断下来。
小结:我们可以把壳假设为一个子程序,当壳把代码解压前和解压后,他必须要做的是遵循堆栈平衡的原理。
因为大家对ESP理解各有异同,但是,大同小异!一般理解可以为:
1、在命令行下断hr esp-4(此时的ESP就是OD载入后当前显示的值)
2、hr ESP(关键标志下一行代码所指示的ESP值(单步通过))
5.总结
现在我们可以轻松的回答一些问题了。
1.ESP定律的原理是什么?
堆栈平衡原理。
2.ESP定律的适用范围是什么?
几乎全部的压缩壳,部分加密壳。只要是在JMP到OEP后,ESP=0012FFC4的壳,理论上我们都可以使用。但是在何时下断点避开校验,何时下断OD才能断下来,这还需要多多总结和多多积累。
3.是不是只能下断12FFA4的访问断点?
当然不是,那只是ESP定律的一个体现,我们运用的是ESP定律的原理,而不应该是他的具体数值,不能说12FFA4,或者12FFC0就是ESP定律,他们只是ESP定律的一个应用罢了!
二 内存断点
1、要解决的问题是:
1.什么是内存断点?
2 .如何在寻找OEP时使用内存断点。
2、内存断点寻找OEP的原理
首先,在OD中内存断点和普通断点(F2下断)是有本质区别的。
内存断点等效于命令bpm,他的中断要用到DR0-DR7的调试寄存器,也就是说OD通过这些DR0-DR7的调试寄存器来判断是否断下普通断点(F2下断)等效于bpx,他是在所执行的代码的当前地址的一个字节修改为CC(int3)。当程序运行到int3的时候就会产生一个异常,而这个异常将交给OD处理,把这个异常给EIP-1以后,就正好停在了需要的中断的地方(这个根据系统不同会不一样),同时OD在把上面的int3修改回原来的代码。
内存断点分为:内存访问断点,内存写入断点。
我们知道,在程序运行的时候会有3种基本的状态产生:读取-->写入-->执行。
004AE242 A1 00104000 mov eax,dword ptr ds:[004AE24C] //004AE24C处的内存读取
004AE247 A3 00104000 mov dword ptr ds:[004AE24C],eax //004AE24C处的内存写入
004AE24C 83C0 01 add eax,1 //004AE24C处的内存执行
1.当对004AE24C下内存访问断点的时候,可以中断在004AE242也可以中断在004AE247。
2.当对004AE24C下内存写入断点的时候,只能中断在004AE247。
3.当执行004AE24C的时候,只能中断在004AE24C
到这里你可能不明白了,为什么内存访问断点能中断在004AE247这一句对004AE24C的写入,而且还能中断在004AE24C的执行呢?其实很简单,我们只要仔细体会一下“内存访问”这四个字的含义遍可以知道,当我们对004AE24C进行读取的时候需要“访问”他吧,当我对004AE24C进行写入的时候也需要“访问”他吧!!当然我们要执行内存地址004AE24C的代码的时候也是还是要“访问”他的!
所以我们不难得出下面的结论:
1.内存写入中断的地方,一定是也可以用内存访问中断。
2.内存执行的地方,也可以用内存访问中断。
如果这时你认为,那么内存写入岂不是没用了。呵呵~那我要告诉你当然不是,如果你想快速的准确的定位到004AE247这一行的时候,那么他就大有作用了!
总结一下:内存断点不修改原代码,不会像普通断点那样因为修改代码被程序校验而导致中断失败;对于区段的访问只是区域大了一点,其原理和上面分析的三行代码是一样的。
ii.如何使用内存断点来寻找OEP呢?
要回答这个问题首先要回答这一个问题:壳是如何解压代码的?
正如我们知道的,壳如果要把原来加密或压缩的代码运行起来就必须要解压和解密原来的代码。而这一个过程我们难道不能将他看做是对代码段(code段)的写入吗?好了,解压完毕了。我们要从壳代码的区段JMP到原来的代码段的时候,难道不正是对代码段(code段)的执行吗?
理清了上面的关系就好办了,那么如果载入OD后,我们直接对code段下内存访问断点的时候,一定会中断在壳对code段的写入的代码的上面,就像上面的004AE247的这一行。而如果当他把code段的代码全部解压解密完毕了以后,JMP到OEP的时候,我们是不是还可以停在OEP的代码上面呢?而且每按下F9都会中断,因为这时code段在执行中哦!
而如果你还要继续问我为什么一定要到那个地方才可以下断呢?我难道不可以一开始就下断吗?
正入我上面所说的,如果你在前面下断很可能壳对code段还没解压完毕呢,这时如果你不停的按F9,你将会看到OD的下方不断的在提示你,“对401000写入中断”“对401002写入中断”“对401004写入中断”.......如果你不介意按F9到他把正个code段写完的话,我除了同情你的“F9”以外,没什么其他的意见!
那么我们就没有别更快一点的办法了吗?
有的!那就是我们呼之欲出的两次内存断点办法。
怎么理解两次内存断点呢?
让我来做一个假设吧,假设我是一个壳的作者。一个EXE文件的有code段,data段,rsrc段.....依次排列在你的内存空间中,那么我会怎么解码呢?呵呵~我比较笨一点,我会先将code段解码,然后再将data段解压,接着是rsrc段......那么你不难发现,只要你在data断或者rsrc段下内存访问断点,那么中断的时候code段就已经解压完毕了。这时我们再对code段下内存访问断点,不就可以到达OEP了吗?
这里注意上面虽然下了两次内存访问断点,但是本质是不一样的,目的也是不一样的。
1.对data段下内存访问断点而中断是因为内存写入中断,目的是断在对对data段的解压时,这时壳要对data段写数据,但是code段已经解压 完毕。
2.对code段下内存访问断点而中断是因为内存执行中断,目的当然就是寻找OEP了。
总结一下:如果我们知道壳在什么地方对code段解压完毕我们就可以使用内存断点,找到OEP。如果不知道,那么我们就依靠2次内存断点去找,如果还不行就用多次内存断点。总之明白了原理在多次的内存断点其实都一样。从这个过程中我们了解的是壳在对区段解码的顺序!
【附加数据处理方法】
【Overlay.exe】
ESP定理马上可以找到OEP
资源需要修复
算出文件的结尾开始地址:00000400+0000C600=0000CA00,把后面的数据完全复制黏贴在新的文件上面就行了。
【自校验的去除】脱壳之后启动之后会自动退出,重新载入分析一下就可以了,技巧是createfile下断点。
【EncryptPE】【反外挂服务器.exe】
忽略所有异常,ESP定理,不过异常的种类比OD配置的多一些,前人的经验,多了如下异常:
这些异常还不是很清楚ANTI是如何触发的,不过忽略之后确实有用。OEP一下子就找到了,然后修复一下数据,搞定。
【Armadillo 1.xx - 2.xx 单线程】
【XDeskWeather】
*******************************************************************************************
1、1.xx--2.xx&单线程&标准方式==========》目标程序“XDeskWeather 3.6(桌面天气秀)”
现在任务管理器中查看是否双进程
*******************************************************************************************
方法:2次断点法,即是:
bp GetModuleHandleA/he GetModuleHandleA/bp GetModuleHandleA+5/he GetModuleHandleA+5
bp GetCurrentThreadId
这种断点是为了解决IAT加密,是一种通用技巧。
*******************************************************************************************
OD,载入。。。。。
004FD379 X>/$ 55 push ebp //程序入口
004FD37A |. 8BEC mov ebp,esp
004FD37C |. 6A FF push -1
下断he GetModuleHandleA,F9运行,注意看堆栈!
7C80B529 k> 8BFF mov edi,edi ;ntdll.7C930738 //停在这里
7C80B52B 55 push ebp
7C80B52C 8BEC mov ebp,esp
7C80B52E 837D 08 00 cmp dword ptr ss:[ebp+8],0
***********************************
每一次F9运行时候,所出现的堆栈情况!
***********************************
0012FF38 004FD441 /CALL 到 GetModuleHandleA 来自 XDeskWea.004FD43B
0012FF3C 00000000 \pModule = NULL
0012FF40 00000000
0012ED48 77F45BB0 /CALL 到 GetModuleHandleA 来自 SHLWAPI.77F45BAA
0012ED4C 77F44FF4 \pModule = "KERNEL32.DLL"
0012ED50 00000001
0012EC88 5D175334 /CALL 到 GetModuleHandleA 来自 COMCTL32.5D17532E
0012EC8C 5D175380 \pModule = "kernel32.dll"
0012EC90 5D1E3AB8 COMCTL32.5D1E3AB8
0012F55C 004F3073 /CALL 到 GetModuleHandleA 来自 XDeskWea.004F306D
0012F560 00000000 \pModule = NULL
0012F564 7C939BA0 返回到 ntdll.7C939BA0 来自 ntdll.7C9399B5
0012C280 00C15331 /CALL 到 GetModuleHandleA 来自 00C1532B //到这一次的时间缓冲有点大
0012C284 0012C3BC \pModule = "kernel32.dll"
0012C288 00000002
此时,取消断点,Alt+F9返回!
00C15331 8B0D 60D8C300 mov ecx,dword ptr ds:[C3D860] //返回到这里
00C15337 89040E mov dword ptr ds:[esi+ecx],eax
00C1533A A1 60D8C300 mov eax,dword ptr ds:[C3D860]
00C1533F 393C06 cmp dword ptr ds:[esi+eax],edi
00C15342 75 16 jnz short 00C1535A
00C15344 8D85 B4FEFFFF lea eax,dword ptr ss:[ebp-14C]
00C1534A 50 push eax
00C1534B FF15 B850C300 call dword ptr ds:[C350B8] ; kernel32.LoadLibraryA
00C15351 8B0D 60D8C300 mov ecx,dword ptr ds:[C3D860]
00C15357 89040E mov dword ptr ds:[esi+ecx],eax
00C1535A A1 60D8C300 mov eax,dword ptr ds:[C3D860]
00C1535F 393C06 cmp dword ptr ds:[esi+eax],edi
00C15362 0F84 AD000000 je 00C15415 //Magic Jump,改jmp!
00C15368 33C9 xor ecx,ecx
00C1536A 8B03 mov eax,dword ptr ds:[ebx]
00C1536C 3938 cmp dword ptr ds:[eax],edi
00C1536E 74 06 je short 00C15376
此时第一个断点的任务完成!
********************************************************************************************
下断bp GetCurrentThreadId,F9,注意观察堆栈!
7C809737 k> 64:A1 18000000 mov eax,dword ptr fs:[18] //停在这里
7C80973D 8B40 24 mov eax,dword ptr ds:[eax+24]
7C809740 C3 retn
*************
0012BB40 73391E36 /CALL 到 GetCurrentThreadId 来自 73391E30
0012BB44 00000001
0012BB48 73391C1A 返回到 73391C1A 来自 73391DE2
0012BB4C 73391B60 返回到 73391B60 来自 73391B8C
0012BB20 7339353F /CALL 到 GetCurrentThreadId 来自 73393539
0012BB24 00000000
0012BB28 734A0470
0012F5A8 00C2CF2D /CALL 到 GetCurrentThreadId 来自 00C2CF27 //到这一次的时间缓冲有点大
0012F5AC 0012FF2C
0012F5B0 00000000
此时,取消断点,Alt+F9返回!
00C2CF2D A3 F018C400 mov dword ptr ds:[C418F0],eax //返回到了这里!
00C2CF32 E8 2487FEFF call 00C1565B
00C2CF37 6A 00 push 0
00C2CF39 E8 4BD9FEFF call 00C1A889
00C2CF3E 59 pop ecx
00C2CF3F E8 7D39FFFF call 00C208C1
00C2CF44 8BF8 mov edi,eax
00C2CF46 A1 E018C400 mov eax,dword ptr ds:[C418E0]
00C2CF4B 8B48 74 mov ecx,dword ptr ds:[eax+74]
00C2CF4E 3348 5C xor ecx,dword ptr ds:[eax+5C]
00C2CF51 3308 xor ecx,dword ptr ds:[eax]
00C2CF53 03F9 add edi,ecx
00C2CF55 8B0E mov ecx,dword ptr ds:[esi]
00C2CF57 85C9 test ecx,ecx
00C2CF59 75 2E jnz short 00C2CF89
00C2CF5B 8B78 5C mov edi,dword ptr ds:[eax+5C]
00C2CF5E E8 5E39FFFF call 00C208C1
00C2CF63 8B0D E018C400 mov ecx,dword ptr ds:[C418E0] ; XDeskWea.0051F258
00C2CF69 FF76 14 push dword ptr ds:[esi+14]
00C2CF6C 8B51 74 mov edx,dword ptr ds:[ecx+74]
00C2CF6F FF76 10 push dword ptr ds:[esi+10]
00C2CF72 33D7 xor edx,edi
00C2CF74 3311 xor edx,dword ptr ds:[ecx]
00C2CF76 FF76 0C push dword ptr ds:[esi+C]
00C2CF79 03C2 add eax,edx
00C2CF7B 8B51 78 mov edx,dword ptr ds:[ecx+78]
00C2CF7E 3351 14 xor edx,dword ptr ds:[ecx+14]
00C2CF81 33D7 xor edx,edi
00C2CF83 2BC2 sub eax,edx
00C2CF85 FFD0 call eax
00C2CF87 EB 25 jmp short 00C2CFAE
00C2CF89 83F9 01 cmp ecx,1
00C2CF8C 75 22 jnz short 00C2CFB0
00C2CF8E FF76 04 push dword ptr ds:[esi+4]
00C2CF91 FF76 08 push dword ptr ds:[esi+8]
00C2CF94 6A 00 push 0
00C2CF96 E8 2639FFFF call 00C208C1
00C2CF9B 50 push eax
00C2CF9C A1 E018C400 mov eax,dword ptr ds:[C418E0]
00C2CFA1 8B48 78 mov ecx,dword ptr ds:[eax+78]
00C2CFA4 3348 5C xor ecx,dword ptr ds:[eax+5C]
00C2CFA7 3348 14 xor ecx,dword ptr ds:[eax+14]
00C2CFAA 2BF9 sub edi,ecx
00C2CFAC FFD7 call edi //直接到这下“硬件执行”断点,F9,取消断点,F7进入
004D12D4 55 push ebp //到这里了,OEP!LordPE-纠正映像-Dump!
004D12D5 8BEC mov ebp,esp
004D12D7 83C4 F0 add esp,-10
004D12DA B8 0C0E4D00 mov eax,XDeskWea.004D0E0C
004D12DF E8 004EF3FF call XDeskWea.004060E4
004D12E4 A1 B06E4D00 mov eax,dword ptr ds:[4D6EB0]
004D12E9 8B00 mov eax,dword ptr ds:[eax]
004D12EB E8 08C0F9FF call XDeskWea.0046D2F8
004D12F0 E8 D7E5FFFF call XDeskWea.004CF8CC
004D12F5 A1 B06E4D00 mov eax,dword ptr ds:[4D6EB0]
004D12FA 8B00 mov eax,dword ptr ds:[eax]
OD,不要关!打开import--选择进程--OEP输入D12D4--自动搜索IAT--获取输入表--显示无效函数--CUT!
这个技巧使用大部分Armadillo版本
【Armadillo 3.78 - 4.xx】
【Jxt】
【ArmaG3ddon v1.9】支持3.78~ 7.7
任务管理器一看,双进程。
遇到过Armadillo的朋友应该知道,它是有点变态的。。中文意思“穿山甲”,可想而知,是很难脱的。
首先介绍一下Armadillo的一些版本以及保护方式、线程情况吧
A:版本
1.xx--2.xx
3.0a--3.61
3.75
3.78
4.x
B:保护方式
标准方式
非标准方式======>Armadillo CopyMem-ll +Debug-Blocker
C:线程
单线程
双线程
上面三种特征都可以两两组合,或者是三三组合。。变化方式之多,可见一斑!下面我将做下总结!希望能够起到抛砖引玉的作用!
*******************************************************************************************
保护方式判断:如果你用脱标准壳的方法去脱不行的话,那么就很有可能是非标准版啦。
线程的判断:方法1、运行程序,打开系统的任务管理器,看看有几个同名进程咯。
方法2、运行程序,打开LordPE,同样是看看有几个同名进程。一个的话就是单进程,两个就是双进程。
*******************************************************************************************
脱壳前的准备:(*****为了节约时间,我在后面将不做说明了,大家要记住!*****)
1、OD设置忽略所有的异常,用隐藏插件隐藏OD!
2、思想准备:Armadillo对断点的检测非常严格,所以我们在设置断点的时候要尽量去使用“硬件执行”
3、概念准备:使用PEID的Armadillo的版本检测一般没那么准确,我倒是发现fi的版本检测还是要强一些
4、Magic Jump:跳转的跨越段一般比较大!(返回时机一定要对!)
5:返回的时机:1、返回的地址是系统领空
2、Shift+F9过程当中,时间缓冲比较大才停下(得自己体会一下)
*******************************************************************************************
吉祥天传世外挂 1.0.0.1
首先PEID查壳是Armadillo 3.78 -> Silicon Realms Toolworks,其实是4.X的版本,而且是个双线程的标准壳!
下面具体的步骤就不写了,就写一些重点吧!
我是在2000下操作的,不知道在XP下是不是好搞点,呵呵
忽略所有异常,手动添加C000001E,E06D7363异常。隐藏OD!
一、双变单(使程序把自己当成子进程运行)
bp OpenMutexA
Ctrl+G:00401000
00401000 60 pushad
00401001 9C pushfd
00401002 68 A0FD1200 push 12FDA0 ; ASCII "44C::DA47D45903"
00401007 33C0 xor eax,eax
00401009 50 push eax
0040100A 50 push eax
0040100B E8 E694A677 call KERNEL32.CreateMutexA
00401010 9D popfd
00401011 61 popad
00401012 - E9 8F9FA777 jmp KERNEL32.OpenMutexA
60 9C 68 A0 FD 12 00 33 C0 50 50 E8 71 8D A8 77 9D 61 E9 74 8E A8 77
二、避开Anti
he OutputDebugStringA
中断2次!
选中%s%之类的字符,点右键->二进制->使用00填充
删除此断点!
三、Magic Jump,避开IAT加密
PS:很奇怪的就是用he GetModuleHandleA+5,却找不到Magic Jump!
bp GetModuleHandleA/he GetModuleHandleA
77E80B1A KE> 55 push ebp //断下,取消这个断点
77E80B1B 8BEC mov ebp,esp
77E80B1D 837D 08 00 cmp dword ptr ss:[ebp+8],0
77E80B21 75 0E jnz short KERNEL32.77E80B31 //F2下断,Shift+F9,断下!注意堆栈!
77E80B23 64:A1 18000000 mov eax,dword ptr fs:[18]
77E80B29 8B40 30 mov eax,dword ptr ds:[eax+30]
77E80B2C 8B40 08 mov eax,dword ptr ds:[eax+8]
001292A4 /0012EBB0
001292A8 |01066AC2 返回到 01066AC2 来自 KERNEL32.GetModuleHandleA
001292AC |0107BD6C ASCII "kernel32.dll"
001292B0 |0107DDAC ASCII "VirtualAlloc"
001292A4 /0012EBB0
001292A8 |01066ADF 返回到 01066ADF 来自 KERNEL32.GetModuleHandleA
001292AC |0107BD6C ASCII "kernel32.dll"
001292B0 |0107DDA0 ASCII "VirtualFree"
00129008 /001292A8
0012900C |01055A99 返回到 01055A99 来自 KERNEL32.GetModuleHandleA
00129010 |0012915C ASCII "kernel32.dll" //取消断点,返回!
01055A99 8B0D 6C500801 mov ecx,dword ptr ds:[108506C] //返回到这里!
01055A9F 89040E mov dword ptr ds:[esi+ecx],eax
01055AA2 A1 6C500801 mov eax,dword ptr ds:[108506C]
01055AA7 391C06 cmp dword ptr ds:[esi+eax],ebx
01055AAA 75 16 jnz short 01055AC2
01055AAC 8D85 B4FEFFFF lea eax,dword ptr ss:[ebp-14C]
01055AB2 50 push eax
01055AB3 FF15 B8620701 call dword ptr ds:[10762B8] ; KERNEL32.LoadLibraryA
01055AB9 8B0D 6C500801 mov ecx,dword ptr ds:[108506C]
01055ABF 89040E mov dword ptr ds:[esi+ecx],eax
01055AC2 A1 6C500801 mov eax,dword ptr ds:[108506C]
01055AC7 391C06 cmp dword ptr ds:[esi+eax],ebx
01055ACA 0F84 2F010000 je 01055BFF //Magic Jump,改jmp!
01055AD0 33C9 xor ecx,ecx
01055AD2 8B07 mov eax,dword ptr ds:[edi]
01055AD4 3918 cmp dword ptr ds:[eax],ebx
01055AD6 74 06 je short 01055ADE
01055AD8 41 inc ecx
01055AD9 83C0 0C add eax,0C
往下拉,找如此类似的序列(一个jnz,一个jmp,两个salc/Magic Jump)
也可以这样做:Ctrl+F在当前位置查找命令: salc
01055C0E ^\0F85 49FEFFFF jnz 01055A5D
01055C14 EB 03 jmp short 01055C19 //F2下断,Shift+F9,断下!取消断点!
01055C16 D6 salc
01055C17 D6 salc
重要:断下后,记得要撤消Magic Jump处的修改!
为何要这样做?我发现程序在下面会依据原先的代码进行解码,
以前下 硬件断点 操作没有修改原代码,所以解码正确。
而直接修改Magic Jump后改变了原先的代码,导致解码不正确而异常出错!
现在我们在解码以前恢复原先的代码,因此就不会再出错了!
此时,打开内存镜像,在00401000段下断,Shift+F9直达OEP!
01070324 8B0C3A mov ecx,dword ptr ds:[edx+edi] //来到这里,F8
01070327 5B pop ebx
01070328 03D7 add edx,edi
0107032A A1 A4100801 mov eax,dword ptr ds:[10810A4]
0107032F 3148 70 xor dword ptr ds:[eax+70],ecx
01070332 A1 A4100801 mov eax,dword ptr ds:[10810A4]
01070337 3148 70 xor dword ptr ds:[eax+70],ecx
0107033A A1 A4100801 mov eax,dword ptr ds:[10810A4]
0107033F 8B16 mov edx,dword ptr ds:[esi]
01070341 8B88 8400000>mov ecx,dword ptr ds:[eax+84]
01070347 3348 60 xor ecx,dword ptr ds:[eax+60]
0107034A 3348 34 xor ecx,dword ptr ds:[eax+34]
0107034D 030D BC10080>add ecx,dword ptr ds:[10810BC] ; FlyWoool.00400000
01070353 85D2 test edx,edx
01070355 75 1E jnz short 01070375
01070357 8B90 8800000>mov edx,dword ptr ds:[eax+88]
0107035D FF76 18 push dword ptr ds:[esi+18]
01070360 3390 8400000>xor edx,dword ptr ds:[eax+84]
01070366 FF76 14 push dword ptr ds:[esi+14]
01070369 3350 40 xor edx,dword ptr ds:[eax+40]
0107036C FF76 10 push dword ptr ds:[esi+10]
0107036F 2BCA sub ecx,edx
01070371 FFD1 call ecx
01070373 /EB 23 jmp short 01070398
01070375 |83FA 01 cmp edx,1
01070378 |75 21 jnz short 0107039B
0107037A |FF76 04 push dword ptr ds:[esi+4]
0107037D |8B90 8800000>mov edx,dword ptr ds:[eax+88]
01070383 |3390 8400000>xor edx,dword ptr ds:[eax+84]
01070389 |FF76 08 push dword ptr ds:[esi+8]
0107038C |3350 40 xor edx,dword ptr ds:[eax+40]
0107038F |6A 00 push 0
01070391 |FF76 0C push dword ptr ds:[esi+C]
01070394 |2BCA sub ecx,edx
01070396 |FFD1 call ecx ; FlyWoool.004B79A6 //F7进去!直接到达OEP!
004B79A6 6A 60 push 60 //OEP!
004B79A8 68 00235D00 push FlyWoool.005D2300
004B79AD E8 26070000 call FlyWoool.004B80D8
004B79B2 BF 94000000 mov edi,94
004B79B7 8BC7 mov eax,edi
004B79B9 E8 E2D1FFFF call FlyWoool.004B4BA0
004B79BE 8965 E8 mov dword ptr ss:[ebp-18],esp
004B79C1 8BF4 mov esi,esp
004B79C3 893E mov dword ptr ds:[esi],edi
004B79C5 56 push esi
004B79C6 FF15 A4445B00 call dword ptr ds:[5B44A4] ; KERNEL32.GetVersionExA
004B79CC 8B4E 10 mov ecx,dword ptr ds:[esi+10]
004B79CF 890D A4367C00 mov dword ptr ds:[7C36A4],ecx
004B79D5 8B46 04 mov eax,dword ptr ds:[esi+4]
LordPE纠正大小Dump!打开Import 1.6,OEP填B79A6,有14个无效指针,全部CUT,正常运行!
【AcProtect】
【AcProtect 123.exe】
本例不处理stolen code ,相对简单
---------------------------------------------------------------------------------
Acprotect1.X之VB程序的处理(高一点的版本。。。。。)
目标程序:估计是个游戏外挂登陆器(网上别人求脱的^_^)
********************************************************************************************
首先Peid查壳,Nothing found *!再看EP区段.perplex,原来是Acprotect1.X版加的壳。
因为是VB程序(跟踪过程中很容易看出来的)
Stolen Code很简单,没有必要苦苦跟踪,VB的IAT加密目前大部分加密软件都是有心无力的。
OD异常设置不忽略内存异常,隐藏OD(估计是高一点版本的Acprotect,因为我有几次隐藏了OD还退出)
这时候反复重新载入几次之后就行了
********************************************************************************************
OD载入程序
00422000 123.<Mod> 55 push ebp //入口
00422001 50 push eax
00422002 E8 01000000 call 123.00422008
00422007 - 7D 83 jge short 123.00421F8C
00422009 C40458 les eax,fword ptr ds:[eax+ebx*2]
0042200C F8 clc
0042200D 66:81E6 4858 and si,5848
F9一下,到最后一次典型异常!
0043374D CD 01 int 1 //最后一次典型异常!注意堆栈!
0043374F 40 inc eax
00433750 40 inc eax
00433751 0BC0 or eax,eax
00433753 75 05 jnz short 123.0043375A
00433755 90 nop
***********************************************
堆栈提示:
0012FF84 0012FFE0 指针到下一个 SEH 记录
0012FF88 00433731 SE 句柄 //右键--转存中跟随--下内存访问断点
0012FF8C 00948A20
***********************************************
下好断点后,Shift+F9运行!
00433731 8B5C24 0C mov ebx,dword ptr ss:[esp+C] //运行到这里,F2下断,Shift+F9运行
00433735 8383 B8000000 02 add dword ptr ds:[ebx+B8],2
0043373C 33C0 xor eax,eax
0043373E C3 retn
00433781 8B048E mov eax,dword ptr ds:[esi+ecx*4] //运行到这里,F2下断,Shift+F9运行
00433784 8B5C8E 04 mov ebx,dword ptr ds:[esi+ecx*4+4>
00433788 2BC3 sub eax,ebx
0043378A C1C8 05 ror eax,5
0043378D 2BC2 sub eax,edx
0043378F 81C2 43A18EAB add edx,AB8EA143
00433795 89048E mov dword ptr ds:[esi+ecx*4],eax //Shift+F9运行后就跳到这里
00433798 49 dec ecx
00433799 ^ EB E1 jmp short 123.0043377C
0043379B 61 popad
0043379C 61 popad
0043379D C3 retn //取消所有的断点[2次F2(INT3断点),1次内存访问断点],F4下来!
************************************************
因为是VB程序,Stolen Code很简单,没必要苦苦跟踪
VB的IAT加密目前大部分加密软件都是有心无力的。
************************************************
鉴于这样。。
打开内存镜像
内存镜像,项目 21
地址=00401000 //F2下断,Shift+F9运行
大小=0001D000 (118784.)
Owner=123 00400000
区段=.text
包含=code
类型=Imag 01001002
访问=R
初始访问=RWE
00401B44 - FF25 9C114000 jmp dword ptr ds:[40119C] ; MSVBVM60.SetMemEvent
00401B4A - FF25 7C114000 jmp dword ptr ds:[40117C] ; MSVBVM60.ThunRTMain //运行到这注意堆栈!
00401B50 47 inc edi
00401B51 6B2B 2E imul ebp,dword ptr ds:[ebx],2E
00401B54 36:E6 96 out 96,al
00401B57 09E5 or ebp,esp
00401B59 73 00 jnb short 123.00401B5B
**********************************************************************
堆栈提示:
0012FFD8 00438CC9 返回到 123.00438CC9 来自 123.00401B4A
0012FFDC 00402C98 ASCII "VB5!6&vb6chs.dll" //要00402C98这个地址
0012FFE0 FFFFFFFF SEH 链尾部
**********************************************************************
现在开始简单处理了。。。
汇编下
00401B4A - FF25 7C114000 jmp dword ptr ds:[40117C] ; MSVBVM60.ThunRTMain
00401B50 68 982C4000 push 123.00402C98 ; ASCII "VB5!6&vb6chs.dll"
00401B55 E8 F0FFFFFF call 123.00401B4A ; jmp to MSVBVM60.ThunRTMain
00401B5A 90 nop
00401B5B 0000 add byte ptr ds:[eax],al
FF 25 7C 11 40 00 68 98 2C 40 00 E8 F0 FF FF FF 90
用OD插件脱壳(纠正OEP为1B50),不用修复直接就可以运行了!
Microsoft Visual Basic 5.0 / 6.0
********************************************************************************************
后记:对Acprotect壳的处理套路大概就是这样了,对这个程序我们没有去处理stolen Code。。。所以显得简单了一些!
【AsProtect 】
【AsProtect emailcaster.exe】
ASProtect 1.23 RC1 -> Alexey Solodovnikov
没有注册的时候有试用提示!
1、OD载入之后忽略除了内存访问之外的所有异常,隐藏OD!Shift+F9,注意堆栈!
0012FF54 018032F0
0012FF58 01811810 ASCII "6uob9ACQoUA=" //硬盘指纹
当第2次出现硬盘指纹的时候,在00401000下F2断点,Shift+F9!
00480650 55 push ebp
00480651 8BEC mov ebp,esp
00480653 8B45 08 mov eax,dword ptr ss:[ebp+8]
00480656 A3 EC7E4800 mov dword ptr ds:[487EEC],eax //487EEC就是保存注册名的位置
0048065B 5D pop ebp
0048065C C2 0400 retn 4
继续Shift+F9运行来到最后一次异常!
01802CD1 3100 xor dword ptr ds:[eax],eax //最后一次异常
01802CD3 64:8F05 0000000>pop dword ptr fs:[0]
01802CDA 58 pop eax
01802CDB 833D 7C6D8001 0>cmp dword ptr ds:[1806D7C],0
01802CE2 74 14 je short 01802CF8
01802CE4 6A 0C push 0C
01802CE6 B9 7C6D8001 mov ecx,1806D7C
01802CEB 8D45 F8 lea eax,dword ptr ss:[ebp-8]
01802CEE BA 04000000 mov edx,4
01802CF3 E8 54E1FFFF call 01800E4C
01802CF8 FF75 FC push dword ptr ss:[ebp-4]
01802CFB FF75 F8 push dword ptr ss:[ebp-8]
01802CFE 8B45 F4 mov eax,dword ptr ss:[ebp-C]
01802D01 8338 00 cmp dword ptr ds:[eax],0
01802D04 74 02 je short 01802D08
01802D06 FF30 push dword ptr ds:[eax]
01802D08 FF75 F0 push dword ptr ss:[ebp-10]
01802D0B FF75 EC push dword ptr ss:[ebp-14]
01802D0E C3 retn //F2下断,Shift+F9运行,注意堆栈
0012FF5C 018148AC
0012FF60 00400000 ASCII "MZP"
0012FF64 C9F5F162
0012FF68 0012FFA4 //要的就是0012FF68 SHE的地址。
hr 0012FF68,F9运行
01815082 03C3 add eax,ebx ; emailcas.00400000 //来到这里,F8
01815084 894424 1C mov dword ptr ss:[esp+1C],eax
01815088 61 popad
01815089 FFE0 jmp eax //跳到OEP
00486718 55 push ebp //OEP
00486719 8BEC mov ebp,esp
0048671B 83C4 F4 add esp,-0C
0048671E B8 18654800 mov eax,emailcas.00486518
00486723 E8 5401F8FF call emailcas.0040687C
00486728 A1 BC814800 mov eax,dword ptr ds:[4881BC]
0048672D 8B00 mov eax,dword ptr ds:[eax]
以下就是脱壳修复了!
用Import REC等级1修复,然后利用插件修复。这时候程序还是未注册版本
最后是以自己的名字注册了!
还记得487EEC就是保存注册名的位置
在数据段00488360写入 注册名字
载入脱壳后修复的文件
命令行DD 487EEC
24894800
00487EEC 017F3861
00487EF0 0000001E
00487EF4 0000001E
修改成
00487EEC 00488360 ASCII "hack by zhxfl"
00487EF0 FFFFFFFF ;记录注册日期
00487EF4 FFFFFFFF;使用日期之类的。
**************
找块空地
00488FE0 63617243
00488FE4 7942206B
00488FE8 C8FDC820
00488FEC 00D0D0CB shell32.00D0D0CB
另外程序有暗桩,怎么去掉见操作!
载入dump_.exe,然后触发安装,直接跳过异常语句即可。
【AcProtect】
【UltraProtect 1.x.EXE】
这里对stolen code的处理比较特别,不是把stolen code寻找出来,而是找另外一个OEP,保留部分壳的信息。
我们脱壳必须知道一些程序的入口特征,关于这个我会做一个专题的(一般是5种程序),下面就介绍一种:
Visual C++的入口特征
push ebp
mov ebp,esp
sub esp,44
push esi
call dword ptr ds:[<&KERNEL32.GetCommandLineA>] ; [GetCommandLineA
mov esi,eax
mov al,byte ptr ds:[eax]
二进制代码
55 8B EC 83 EC 44 56 FF 15 E0 63 40 00 8B F0 8A 00
此例作为脱壳示例,只是想起到抛砖引玉的作用!
********************************************************************************************带发修行ACProtect v1.21=========>UltraProtect 1.x -> RISCO Software Inc.
********************************************************************************************Od设置不忽略内存异常,其余异常全部忽略
载入,隐藏!
0040D000 U> 60 pushad //入口,F8一下!
0040D001 70 02 jo short UltraPro.0040D005 //注意ESP值(0012FFA4)
0040D003 D3FE sar esi,cl
0040D005 C1D6 12 rcl esi,12
0040D008 FC cld
0040D009 F9 stc
我们下断hr 0012FFA4,F9运行,这里ESP定律要分7对中断
0041E6FF 61 popad //1
0041E700 56 push esi ; ntdll.77F57D70
0041E701 BE A3DE4000 mov esi,UltraPro.0040DEA3
0041E750 60 pushad
0041E751 E8 0ABDFFFF call UltraPro.0041A460
0041E756 E8 00000000 call UltraPro.0041E75B
0041E768 899D AAD24000 mov dword ptr ss:[ebp+40D2AA],ebx
0041E76E 61 popad //2
0041E76F 890F mov dword ptr ds:[edi],ecx
0041E7BF 60 pushad
0041E7C0 E8 9BBCFFFF call UltraPro.0041A460
0041E7C5 E8 34BAFFFF call UltraPro.0041A1FE
0041E7D0 61 popad //3
0041E7D1 8B0B mov ecx,dword ptr ds:[ebx]
0041E7D3 8F05 93DE4000 pop dword ptr ds:[40DE93]
0041E821 60 pushad
0041E822 E8 39BCFFFF call UltraPro.0041A460
0041E827 C685 D0D14000 00 mov byte ptr ss:[ebp+40D1D0],0
0041E82E 61 popad //4
0041E82F FF35 EBDE4000 push dword ptr ds:[40DEEB]
0041E835 57 push edi
0041E87F 60 pushad
0041E880 E8 15DEFFFF call UltraPro.0041C69A
0041E885 61 popad //5
0041E886 8F05 B7DE4000 pop dword ptr ds:[40DEB7] ; UltraPro.0040DF0B
0041E88C FF35 B7DE4000 push dword ptr ds:[40DEB7]
0041E8D6 60 pushad
0041E8D7 E8 5BDBFFFF call UltraPro.0041C437
0041E8DC 61 popad //6
0041E8DD FF35 CFDE4000 push dword ptr ds:[40DECF]
0041E8E3 56 push esi
0041E92D 60 pushad
0041E92E E8 86FDFFFF call UltraPro.0041E6B9
0041E933 61 popad //7
0041E934 8F05 73DE4000 pop dword ptr ds:[40DE73] ; ntdll.77F944A8 //这里就是代发修行的最佳脱壳地点,此时对资源和代码已经完全解压。OD插件,DUMP!
大家可以看出 +++++++以上对应7句保护Call,为什么要算清楚是7句呢?,到伪造入口就明白。+++++++
另外怎么去知道那里才是带发修行的好地方呢?其实很简单~等下你就明白了!(嘿嘿~知道了吧~就是相当于最后一次ESP
分段了!)
F9继续运行!
0041BAAD CD 01 int 1 //中断在这里,取消硬件断点!
0041BAAF 40 inc eax
0041BAB0 40 inc eax
0041BAB1 0BC0 or eax,eax
0041BAB3 75 05 jnz short UltraPro.0041BABA
0041BAB5 90 nop
0041BAB6 90 nop
我们ALT+M 打开内存镜像,在00401000(Code)段F2下断,Shift+F9运行!
004010DD 3C 22 cmp al,22 //到这里了,伪OEP!
004010DF 75 1B jnz short UltraPro.004010FC
004010E1 56 push esi
004010E2 FF15 F4644000 call dword ptr ds:[4064F4] ; UltraPro.0040D4D6
004010E8 8BF0 mov esi,eax
我们按住Crtl+向上箭头,往上翻看(防止代码混乱-找真OEP!)
004010CC 95 xchg eax,ebp //真OEP,但是代码被抽取了!
004010CD 61 popad
004010CE 2E:EF out dx,eax
004010D0 D1AD 26477503 shr dword ptr ss:[ebp+3754726],1
004010D6 8730 xchg dword ptr ds:[eax],esi
004010D8 3C A2 cmp al,0A2
004010DA ^ 78 84 js short UltraPro.00401060
004010DC 7F 3C jg short UltraPro.0040111A
现在就是还原代码了~
55 8B EC 83 EC 44 56 FF 15 E0 63 40 00 8B F0 8A 00
二进制粘帖!(其实这一步不用这么做的^_^,呵呵~如果用其他方法就得这么做了!)
这里,我们获取真、伪OEP只是方便修复IAT,其实壳早就在0041E934处解码完毕了!
关掉OD,打开加壳程序(因为我们使用跟踪等级3修复的时候,如果开着OD,ImportREC会死掉的!)
运行ImportREC,选择这个进程。把OEP改为000010CC,点IT AutoSearch,点“Get Import”,指针部分有效,用跟踪等级3全部修复,把OEP改为1E934(0041E934-00400000),修复程序,正常运行。
PS:如果还是死掉的话~我们就分段修复吧~一回少修复一点!
脱壳文件显示Nothing found *呵呵~其实壳已经脱掉了,这样的显示是因为加壳的缘故了~很正常!!
【ASProtect 1.23 RC4 - 1.3.08.24 -> Alexey Solodovnikov 以壳脱壳】
【以壳脱壳原理】
1.以壳解壳的原理I.什么是stolen code。===================== 关于stolen bytes ===================== 稍微说明一下: 每一种编译工具例如 : VC++ , Delphi , Borland , etc.. 在OEP有一个唯一的/相同的PE头 其中的一些是这样的:
Push EBP MOV Ebp,Esp Add ESP , -010 Mov EAX, SOME_VALUE
(共11bytes) 或者:
Push EBP MOV Ebp,Esp ;* Add ESP , -010 ;**Push EBX ;***Push ESi Push EDi Mov EAX, SOME_VALUE ;****
(共14 bytes)
1.对于*的部分原程序的OEP,通常是一开始以 Push EBP 和MOV Ebp,Esp这两句开始的,不用我多说大家也知道这两句的意思是以EBP代替ESP,作为访问堆栈的指针。为什么要这样呢?为什么几乎每个程序都是的开头能?因为如果我们写过C等函数的时候就应该清楚,程序的开始是以一个主函数main()为开始的,而函数在访问的过程中最重要的事情就是要确保堆栈的平衡,而在win32的环境下保持平衡的办法是这样的:1.让EBP保存ESP的值;2.在结束的时候调用mov esp,ebp pop ebp retn或者是leaveretn两个形式是一个意思。这样做的好处是不用考虑ESP等于多少,PUSH了多少次,要POP多少次了,因为我们知道EBP里面放的是开始时候的ESP值。
2.对于**的部分Add ESP , -010这种代码的意思是在堆栈区域开辟一块区域保存和使用局部变量,用EBP-XX来调用。
3.对于***的部分
在下来就是保存寄存器的初始值。
4.对于****的部分
初始化寄存器。
小节:我们知道了这就是程序在编译后程序OEP的一般形式,而某些壳在处理OEP的代码时,把这些固定的代码nop掉,然后把他们放到壳代码的空间里面(而且还常伴随着花指令)!使原程序的开始从壳空间开始,然后再JMP回程序空间。如果我们脱掉壳了以后,这一部分就会遗失,也就达到了反脱壳的目的。这就是stolen code技术,或者更确切的说是stolen OEP code技术。
II.Replace Code
这是一种将原程序代码抽出,放到壳代码中执行的技术。应该就是一般说的SDK(Software Development Kit)技术。(其实我也不是很懂^^)
怎么实现的不清楚,但是他是如何体现出来的呢?
当你脱完壳了以后,运行发现提示“XXXXXX处不易读取”十有八九就是因为采用了SDK技术。因为当我们脱壳后这部分代码都没有了,我们怎么能读取呢?
总之我把replace code看成是又一种形式的stolen code,他偷掉的是程序中的的code。
III.以壳解壳的提出 上面的两种反脱壳的技术是横在我们面前的拦路虎,我们如何解决他呢?
办法有2个:
1.跟踪并且分析代码然后自己补充完整。
2.用以壳解壳的办法。
对于一些stolen OEP code我们好象还可以接受(还不太多嘛),但是如果SDK把成段成段的抽调代码,那我估计你能把那些代码补全了还不如自己去去把这个程序写出来^-^。而我们知道这些被偷掉的代码全在壳里面,只不过他不属于程序的空间,所以我们不能把他dump下来。那么我们想:如果我们把他们全都dump下来以后,那不就不用自己去补了。在这种想法的促使下,以壳解壳的方法诞生了。
接下来的问题便是:我们怎么dump下来呢?
但是在这个问题的前面应该是dump什么部分?按照前面所说的,如果我们在dump下程序了以后运行发现程序在读某一块内存区域,但是那一块区域却什么都没有,这时你便应该知道要dump什么区域了吧!
那么如何dump呢?
使用LordPE的 dump region...(区域dump)功能就可以了,选种自己想要的区域就可以直接dump下来了!
在接下来是该如何装入原来的文件呢?
先给大概的出步骤:
1.使用PE Editor的Load section from disk...(从硬盘载入区段头)功能增加一个区域,放入壳代码;
2.修改那个新区段的RVA;3.重建PE文件(在重建选项一般保留“验正PE”就可以了)
对于1没什么好说的,我们来解释一下为什么要修改这个RVA。
代码在文件中有他们自己的位置,我们称为文件地址。而当他映射到内存的时候并不是像文件中的地址那样排列。他是按照RVA(相对虚拟地址)的地址+基址 来确定自己在内存中的位置的。所以我们要将原来壳代码所在的位置减掉基址添入就可以了。编辑使用edit section head....的功能。最后因为实际的PE文件和PE头里面的信息有写不一样(你都添加了一个区段当然不一样了),那么需要修复PE头,所以只选用验正PE,不建议在这个时候优化程序,因为我们一般的步骤是先添加区段壳代码,然后修复IAT,这个也是是要添加一个区段的哦!
----------------------------------------------------------------3.总结 现在我们来回答开始提出的三个问题:
1.什么是以壳解壳? 以壳解壳是针对主程序的部分代码被偷,进而提出来的一种解决办法。采用添加原壳代码的的手段,达到使程序运行时仍能像未脱壳以前那样正确的访问到壳代码空间。可以说是一种“懒”办法,但是对于某些程序被偷得太多的时候却是一种无奈之举!
2.什么时候要以壳解壳? 当你发现被偷掉的代码很多,自己不能手动补充完整的时候。
3.如何以壳解壳?
上面给出了一个以壳解壳的实例。下面也是一个(明天再帖^^)
4.以壳解壳有什么不足?
因为以壳解壳采用了壳中的代码,那么如果在壳中代码中有部分是校验,或者是一些检验脱壳的代码,那么我们无异于是引狼入室。而且保留了壳代码,不仅增加了文件大小而且留下了原程序本来就没有的东西,总让人心理不是很爽。所以我的向来主张是以壳解壳的办法是最后的救命稻草,不要太过于依赖。
5.什么时候不能使用以壳解壳的办法?
当壳代码的RVA小于基址的时候!上面的方法将不在适用。
例如:壳代码的RVA=300000 而程序的基址=400000。
那时我们怎么修改这个RVA呢?我还没有找到合适的办法,期待那位能告诉我 ^-^。
问题在这个帖子里面解决了:
【以壳脱壳 实例 ASProtect 1.23】
OD设置忽略除了内存访问之外的所有异常!
00401000 cry> 68 01009000 push crysb.00900001 //入口!
00401005 E8 01000000 call crysb.0040100B
0040100A C3 retn
0040100B C3 retn
0040100C EB 6E jmp short crysb.0040107C
0040100E C2 6873 retn 7368
Shift+F9走!第23次的时候第2次看到硬盘指纹。。。
016D46A5 3100 xor dword ptr ds:[eax],eax //第23次
016D46A7 EB 01 jmp short 016D46AA
016D46A9 68 648F0500 push 58F64
016D46AE 0000 add byte ptr ds:[eax],al
016D46B0 00EB add bl,ch
堆栈提示:
0012FF50 016C0000
0012FF54 016A0000
0012FF58 016D4138
0012FF5C 016E94E4 ASCII "6uob9ACQoUA="
0012FF60 016D3616 返回到 016D3616 来自 016C2524
0012FF64 016A0000
在CODE段下断,Shift+F9运行!
004085E0 8B4424 04 mov eax,dword ptr ss:[esp+4] //到这里!
004085E4 A3 98324C00 mov dword ptr ds:[4C3298],eax //[4C3298]是保存注册地址的
004085E9 C2 0400 retn 4
继续Shift+F9运行,第26次到达最后一次异常!
016D39EC 3100 xor dword ptr ds:[eax],eax //最后一次异常
016D39EE 64:8F05 0000000>pop dword ptr fs:[0]
016D39F5 58 pop eax
016D39F6 833D B07E6D01 0>cmp dword ptr ds:[16D7EB0],0
016D39FD 74 14 je short 016D3A13
016D39FF 6A 0C push 0C
016D3A01 B9 B07E6D01 mov ecx,16D7EB0
016D3A06 8D45 F8 lea eax,dword ptr ss:[ebp-8]
016D3A09 BA 04000000 mov edx,4
016D3A0E E8 2DD1FFFF call 016D0B40
016D3A13 FF75 FC push dword ptr ss:[ebp-4]
016D3A16 FF75 F8 push dword ptr ss:[ebp-8]
016D3A19 8B45 F4 mov eax,dword ptr ss:[ebp-C]
016D3A1C 8338 00 cmp dword ptr ds:[eax],0
016D3A1F 74 02 je short 016D3A23
016D3A21 FF30 push dword ptr ds:[eax]
016D3A23 FF75 F0 push dword ptr ss:[ebp-10]
016D3A26 FF75 EC push dword ptr ss:[ebp-14]
016D3A29 C3 retn //F2断下来,注意堆栈!
堆栈提示:
0012FF5C 016E7E9C
0012FF60 00400000 crysb.00400000
0012FF64 574F42C8
0012FF68 0012FFA4 =======>0012FF68
0012FF6C 016C0000
hr 0012FF68,F9运行!
016E8019 /EB 44 jmp short 016E805F //到这里,删除断点,F7一下!
016E801B |EB 01 jmp short 016E801E
016E801D |9A 51579CFC BF0>call far 00BF:FC9C5751
016E8024 |0000 add byte ptr ds:[eax],al
016E8026 |00B9 00000000 add byte ptr ds:[ecx],bh
016E802C |F3:AA rep stos byte ptr es:[edi]
016E805F 03C3 add eax,ebx //到这里,F8一下!
016E8061 BB C4000000 mov ebx,0C4 //这里就是我们以壳解壳的OEP=012E8061
016E8066 0BDB or ebx,ebx
016E8068 75 07 jnz short 016E8071
016E806A 894424 1C mov dword ptr ss:[esp+1C],eax
016E806E 61 popad
打开LordPE,完全DUMP这个进程!再区域脱壳Region00E50000-00E5C000.dmp(016E0000-00400000=012E0000)
(dump下来的区块必须包含以壳脱壳的OEP的低值范围)
组装Unpack.exe
按PE编辑器,导入dump.exe,按区段编辑,右键,导入dump下来的区段。这时候还需要编辑区段头OEP在这个区段里面,这个区块的基地址必须减去原来的40000,然后这个基地址就作为新的OEP基地址。参考Region00E50000-00E5C000.dmp看到新的基地址就是E50000-40000=E10000,改好之后保存,然后重建PE,选中dump PE。
请出AsprDbgr 修复输入表!
AsprDbgr v1.0beta (:P) Made by me... Manko.
iEP=401000 (C:\Program Files\CrystalButton2\crysb.exe)
IAT Start: 492000
End: 492730
Length: 730
IATentry 492208 = 16D1CD8 resolved as GetCommandLineA
IATentry 492224 = 16D1C64 resolved as GetModuleHandleA
IATentry 492244 = 16D17A4 resolved as GetProcAddress
IATentry 492288 = 16D1CC8 resolved as LockResource
IATentry 492298 = 16D1C8C resolved as GetVersion
IATentry 492320 = 16D1CB8 resolved as GetCurrentProcess
12 invalid entries erased.
Dip-Table at adress: 16D7AB4
0 4085E0 0 0 0 0 0 0 0 0 0 0 0 0
Last SEH passed. (16D39EE) Searching for signatures. Singlestepping to OEP!
Call + OEP-jump-setup at: 16E6049 ( Code: E8000000 5D81ED )
Mutated, stolen bytes at: 16E6095 ( Code: EB02CD20 EB02CD20 )
Erase of stolen bytes at: 16E5FF8 ( Code: 9CFCBF37 606E01B9 )
Repz ... found. Skipping erase of stolen bytes. ;)
possible (temp)OEP: 4364B6 (Reached from preOEP: 16E6009)
打开IR1.6,在OEP处添0364B6,获取输入表全部有效--再把OEP改成以壳脱壳的OEP--修复抓取文件!
呵呵~可以运行,,现在我们来Pre-Dip注册一下~~
OD载入Unpack_.exe
还记得4C3298?
DD 4C3298
004C3298 016C3861 Unpack_.016C3861
004C329C 6D6F6F7A
004C32A0 00000000
004C32A4 00007963
找块空地。。我找004DFFF4写入******
现在修改成
004C3298 004DFFF4 ASCII "******"
004C329C 6D6F6F7A
004C32A0 00000000
004C32A4 00007963
因为没有试用标志。。。就不用改了
现在复制可执行文本--覆盖保存!
运行看看。。。呵呵已经注册给******了。。
抓个图留恋吧。。。到此为止。。。
***********
这里演示如何跟踪 stolen code。
Stolen Code
push ebp
mov ebp,esp
push -1
push 49A4A8
push 4363B8
mov eax,dword ptr fs:[0]
push eax
mov dword ptr fs:[0],esp
sub esp,58
push ebx
push esi
push edi
mov dword ptr ss:[ebp-18],esp
55 8B EC 6A FF 68 A8 A4 49 00 68 B8 63 43 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58
53 56 57 89 65 E8
【UltraProtect 1.x -> RISCO Software Inc.】
【stolen code 的寻找】
【必须声明的是这个版本的壳有好几种保护方法,每种都需要不同的技巧。】
【完美卸载XP V9.14】
******************************************************************
Od设置不忽略INT3中断,其余异常全部忽略。隐藏!
OD载入
004AC000 N> 60 pushad //记下004AC000,这个后面要用到的!
004AC001 4E dec esi
004AC002 D3D6 rcl esi,cl
004AC004 4E dec esi
004AC005 66:D3E8 shr ax,cl
F9运行。
004BAB23 90 NOP //第一次也是最后一次INT3异常。
004BAB24 64:67:8F06 0000 POP DWORD PTR FS:[0]
004BAB2A 83C4 04 ADD ESP,4
004BAB2D 60 PUSHAD
004BAB2E E8 00000000 CALL NetClean.004BAB33
004BAB33 5E POP ESI
004BAB34 83EE 06 SUB ESI,6
004BAB37 B9 5B000000 MOV ECX,5B
004BAB3C 29CE SUB ESI,ECX
004BAB3E BA 09E5B87E MOV EDX,7EB8E509
004BAB43 C1E9 02 SHR ECX,2
004BAB46 83E9 02 SUB ECX,2
004BAB49 83F9 00 CMP ECX,0
004BAB4C 7C 1A JL SHORT NetClean.004BAB68
.................................................
堆栈内容
0012FF58 0012FFE0 指针到下一个 SEH 记录
0012FF5C 004BAAF0 SE 句柄 //右键对004BAAF0转存中跟随,下内存访问断点,Shift+F9!
0012FF60 F9E1E5CE
004BAAF0 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4] //下断点Shift+F9中断1
004BAAF4 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C]
004BAAF8 FF81 B8000000 INC DWORD PTR DS:[ECX+B8]
004BAAFE 8B00 MOV EAX,DWORD PTR DS:[EAX]
004BAB00 2D 03000080 SUB EAX,80000003
004BAB05 75 12 JNZ SHORT NetClean.004BAB19
004BAB07 90 NOP
004BAB08 90 NOP
004BAB09 90 NOP
004BAB0A 90 NOP
004BAB0B 33C0 XOR EAX,EAX
004BAB0D 8941 04 MOV DWORD PTR DS:[ECX+4],EAX
004BAB10 8941 08 MOV DWORD PTR DS:[ECX+8],EAX
004BAB13 8941 0C MOV DWORD PTR DS:[ECX+C],EAX
004BAB16 8941 10 MOV DWORD PTR DS:[ECX+10],EAX
004BAB19 C3 RETN
.................................................
004BAB4E 8B048E MOV EAX,DWORD PTR DS:[ESI+ECX*4] //下断点Shift+F9中断2,清除内存断点
004BAB51 8B5C8E 04 MOV EBX,DWORD PTR DS:[ESI+ECX*4+4]
004BAB55 03C3 ADD EAX,EBX
004BAB57 C1C8 0E ROR EAX,0E
004BAB5A 2BC2 SUB EAX,EDX
004BAB5C 81EA D41CF55C SUB EDX,5CF51CD4
004BAB62 89048E MOV DWORD PTR DS:[ESI+ECX*4],EAX
004BAB65 49 DEC ECX
004BAB66 ^ EB E1 JMP SHORT NetClean.004BAB49
004BAB68 61 POPAD
004BAB69 61 POPAD
004BAB6A C3 RETN //F4直接下来,这时是寻找Stolen Code时候了。
.................................................
再次点它的死穴。
命令行 d 12ffc0。
右键下硬件访问dword断点!
004C9B31 55 PUSH EBP //Stolen Code
004C9B32 8BEC MOV EBP,ESP //Stolen Code
004C9B34 6A FF PUSH -1 //Stolen Code
004C9B36 90 NOP
004C9B37 60 PUSHAD
004C9B38 60 PUSHAD
这个程序抽了5个字节。
........................................................................
ALT+M 打开内存镜像断点,对准它的第二个死穴点。
内存镜像, 项目 12
地址=00401000 //Code段下内存访问断点
大小=00047000 (290816.)
Owner=NetClean 00400000
区段=.text
Contains=code
类型=Imag 01001002
访问=R
初始访问=RWE
F9运行
004431F9 68 D8B24400 PUSH NetClean.0044B2D8 //临时Oep,滚动条向上看,如何判断抽掉多少字节,用滚动条是代码会混乱,右键分析代码,如我现在调整的样式,标签1
004431FE 68 B4334400 PUSH NetClean.004433B4 ; JMP to MSVCRT._except_handler3
00443203 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
00443209 50 PUSH EAX
0044320A 64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00443211 83EC 68 SUB ESP,68
00443214 53 PUSH EBX
00443215 56 PUSH ESI
00443216 57 PUSH EDI
.............................................................................
标签1
004431F4 8C DB 8C //真Oep
004431F5 . C3 RETN
004431F6 49 DB 49 ; CHAR 'I'
004431F7 2E DB 2E ; CHAR '.'
004431F8 79 DB 79 ; CHAR 'y'
004431F9 . 68 D8B24400 PUSH NetClean.0044B2D8
004431FE . 68 B4334400 PUSH NetClean.004433B4 ; JMP to MSVCRT._except_handler3; SE handler installation
00443203 . 64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00443209 . 50 PUSH EAX
0044320A . 64:8925 00000>MOV DWORD PTR FS:[0],ESP
00443211 . 83EC 68 SUB ESP,68
00443214 . 53 PUSH EBX
00443215 . 56 PUSH ESI
00443216 . 57 PUSH EDI
00443217 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
0044321A . 33DB XOR EBX,EBX
0044321C . 895D FC MOV DWORD PTR SS:[EBP-4],EBX
0044321F . 6A 02 PUSH 2
00443221 . FF15 70874400 CALL DWORD PTR DS:[448770] ; MSVCRT.__set_app_type
.............................................................................
还原代码!
55 8B EC 6A FF
004431F4 55 PUSH EBP //用Od插件修正入口为431F4直接脱壳吧,重建输入表的勾去掉
004431F5 8BEC MOV EBP,ESP
004431F7 6A FF PUSH -1
004431F9 . 68 D8B24400 PUSH NetClean.0044B2D8
004431FE . 68 B4334400 PUSH NetClean.004433B4 ; JMP to MSVCRT._except_handler3; SE handler installation
00443203 . 64:A1 0000000>MOV EAX,DWORD PTR FS:[0]
00443209 . 50 PUSH EAX
0044320A . 64:8925 00000>MOV DWORD PTR FS:[0],ESP
00443211 . 83EC 68 SUB ESP,68
00443214 . 53 PUSH EBX
00443215 . 56 PUSH ESI
00443216 . 57 PUSH EDI
00443217 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
0044321A . 33DB XOR EBX,EBX
0044321C . 895D FC MOV DWORD PTR SS:[EBP-4],EBX
0044321F . 6A 02 PUSH 2
00443221 . FF15 70874400 CALL DWORD PTR DS:[448770] ; MSVCRT.__set_app_type
........................................................................
修复IAT必须关闭OD单独开加壳程序修复,不然ImportREC停止响应,最后用ImportREC Oep填431F4,跟踪等级三轻松修复,有10个指针提示无法修复,你可以验证一下,经过验证全部是垃圾指针,通常ImportREC可全部修复指针,如有没有一般都是垃圾,拿剪刀全部Cut掉,修复后无法运行。
寻找出错原因。
004431C4 |. 68 00404500 PUSH 2_.00454000
004431C9 |. E8 DC000000 CALL <JMP.&msvcrt._initterm> //这个Call可能是新版Acprotect的解码技术,进这个Call里面,循环解码,没解完程序就崩溃。
004431CE |. 83C4 24 ADD ESP,24 //这里类似代码,我没有再次跟踪。
其实本版本Acprotect嵌有Oep处代码检验程序,发现Oep处代码被替换,立即拒绝解码,你失去了关键的代码当然程序无法运行,还要承认N次错误确定按钮。
004C9B31 55 PUSH EBP //Stolen Code
004C9B32 8BEC MOV EBP,ESP //Stolen Code
004C9B34 6A FF PUSH -1 //Stolen Code
我们已经掌握。
004431F9 . 68 D8B24400 PUSH NetClean.0044B2D8 //临时Oep也知道。
现在做什么,让程序认为你没有脱壳,将perplex段里面有用的内容全部解码。
方法
PUSH EBP //Stolen Code
MOV EBP,ESP //Stolen Code
PUSH -1 //Stolen Code
jmp 004431F9
Od载入脱壳修复后的程序,Ctrl+G 004AC000,右键清除分析。
004AC000 60 PUSHAD //4AC000是原来壳的入口点,将Oep入口代码复制到这里。
004AC001 4E DEC ESI
004AC002 D3D6 RCL ESI,CL
004AC004 4E DEC ESI
004AC005 66:D3E8 SHR AX,CL
004AC008 4E DEC ESI
004AC009 8BC3 MOV EAX,EBX
004AC00B 48 DEC EAX
004AC00C 7A 03 JPE SHORT Unpack_.004AC011
004AC00E 7B 01 JPO SHORT Unpack_.004AC011
004AC010 7A C1 JPE SHORT Unpack_.004ABFD3
004AC012 EF OUT DX,EAX ; I/O 命令
004AC013 F0:50 LOCK PUSH EAX ; 锁定前缀是不允许的
004AC015 E8 01000000 CALL Unpack_.004AC01B
.........................................................
55 8B EC 6A FF
jmp 004431F9
004AC000 55 push ebp
004AC001 8BEC mov ebp,esp
004AC003 6A FF push -1
004AC005 - E9 EF71F9FF jmp dump1_.004431F9
004AC00A C3 retn
004AC00B 48 dec eax
004AC00C 7A 03 jpe short dump1_.004AC011
004AC00E 7B 01 jpo short dump1_.004AC011
004AC010 7A C1 jpe short dump1_.004ABFD3
004AC012 EF out dx,eax
004AC013 F0:50 lock push eax ; 不允许锁定前缀
...........................................................
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
- [求助][求助]调试驱动用什么调试器 4150
- [原创]八数码演示(开源) 5137
- [求助]如何获取U盘插入的消息 4383
- [讨论]看了版主强制删除的代码,抛出几个疑问 4897
- [讨论]结贴。。。 3902
谁下载
kitty
systembug
疯子阿虹
tfrist
崂山道士
guaji
DX_BABY
请哥慢捂
ttstation
tshalan
chenfeng
clearsky
曾经来过
lanshuguan
herowuking
今生缘
careton
tianwenle
蔚黑
qazwsxedcr
liutrocal
老道
zoyu
苏打
jordonA
长发飘飘
zylzylzyl
dfjss
leeone
elfchery
langyashan
DuoLaMMeng
红尘颠倒
cangdawei
寻梦小子
haoliao
bbsphixy
pengqiyun
waidao
kjms
tokiii
doshacker
小覃
vkoyo
小小的心
hkzjms
kojhlong
sunlulu
zhxfl
豆浆蟹蟹
网络小牛
逍遥枷锁
ROC威鹏
imitation
windowsa
丫丫journey
Y风情
leonardluo
乐呵呵堂
mzhsy
huoquan
momonippp
huanggx
junjunniu
lianglebin
hgenek
MoonFlower
酷爱小铅
ntfans
gillyoyo
idhyt
qmxkiller
jijiwaiwa
梦想未来
hackbs
mamingxiu
infoteam
小闹空间
户大
hbszsd
麦田小虫
韩立l
zhang张张张
学者learner
zhclgmfz
zx_571392
网马
熔岩
anglehua
Darkin
逍遥m
怕怕吓一
theusersix
wllmsdn
汤鹏
MoyuSgs
轩辕追命
xingquane
吉吉哥
hancool
看原图
赞赏
雪币:
留言: