实践的目标程序是: Aspack 2000.exe
Aspack是一个执行程序的压缩壳,详情请参看它的网站:http:// www.aspack.com
Aspack2000.exe本身就是用Aspack 来加壳的!
上一个版本的Aspack( 108.3)已经包含了了某些烦人的特征:
-Aspack对允许对一个程序进行多层压缩加壳,在有些情况下,procdump的自动脚本将对它无能为力, 因而,必须采用全手动DUMP的方法.Advanced Registry Tracer 1.0a就是分三次压缩的.
-在脱壳后,无法获得清晰的输入函数表.(部分的输入表将被Aspack的装载器损坏)。
Aspack 2000的版本的特征与以上的版本基本一致,只是增多了对SOFTICE的检验和对PE LOADER被修改的检验功能.
目标: 获取Aspack 2000在Wdasm下带有清晰的函数表的脱壳版.
工具: SoftIce (谢谢Numega! ), Procdump (谢谢G-Rom, Lorian & Stone ! ! ), FrogsICE (谢谢Frog s_Print!! ), Hexworks30 (谢谢… 噢… BpSoft !)
方法: 我将试着找出一种比较通用的,操作起来比较简单的方法 (尽可能也适应别的壳的?)....由您来裁定吧.
我将介绍分为4个步骤:
-手动DUMP出输入函数表,在它还是"干净"的时候 (SoftIce + procdump或者IceDump)
-手动在程序执行前DUMP出它的脱壳程序 (SoftIce + procdump)
-把DUMP出的输入表插入脱壳后的程序里(hexworks30)
-在directory Import table里,将入口处(entry point)及地址升级 (procdump)
埋头苦干前的准备工作:
1 - Anti-SoftIce
为了安心工作,首先要干掉Aspack对SICE的侦查功能:
有几个方法,和一个优秀的工具“FrogsIce” (谢谢Frog's print ).
在求知欲和测试另一种方法的好奇心驱使下,我在WINICE.EXE文件里, 用十六位编辑器把“SICE”的字符串替改成了“SoCE”,然后重新启动电脑.
呵呵, 这样足够让Aspack在内存里检查不出SoftIce.
我向你尽力推荐使用FrogsICE .(再次感谢Frog s_Print!)
-收集Aspack的 PE Header 和Directory Import 的信息.
在Procdump里,点击PE Editor 并且打开Aspack2000.exe,以取得有用的信息. (这里用重写及红色表示) :
第一在输入表中引起我们注意的:
这里,输入表的RVA与IDATA节里的Virtual Offset 不一致.( 00066D1C 代替了 00046000).它指向.ASP节里面.(一个为了aspack装载器必须的节?)
执行方法:
根据Aspack的装载者器必须在某个时候, 将它自己压缩的数据解压,并且将idata节重建为原来的样子的原则,它得必须写那些字节在它原来的位置!
也就是说,从Virtual Offset 46000 (就是 400000 + 46000 = 446000)
幸运的话,特别一个BPM 446000 W 我们将被通知idata节的恢复。
凭着研究过Aspack 108.3壳的经验, (要是原则至今没有改变),我知道它将读取那些被压缩的数据,将它们解压在缓冲内存里,然后将解压后的区域复制到它原来的地方.(即446000).
这个,有多少层压缩,它就重复多少次.
剩下的,我们就可以观察每次截止时在446000区域的内容,直到它干净为止.
(经过以上的练习,我们现在就象小孩子玩游戏一样简单了.)
每次截停代表一层压缩.
在几秒钟内,我们就可以知道多少层压缩被用在这个程序上.
步骤一 : 手动DUMP出输入表,当这个表还是“干净”时.
我们要放个bpm在ds:00446000的地址,在装载器开始解压数据前,我们要在softIce下设置一个断点, 同时乘机下个bpm, 以下是具体的步骤: (读起来长,但实际操作起来很简单!)
CRTL+D转到Sice下:
BPX getprocaddress或BPX getversionexa (在这里,bpx getprocaddress就足够了)
X或F5为了回到WINDOWS, 和执行Aspack2000.exe
POP!截住了!
F12来到Aspack代码领空.
我们用BD来取消bpx,然后 BPM ds :446000 W
(我们可来个D 446000来检测.idata节没有被动过,只有些 ????)
X或F5,为了让Aspack的装载器继续工作
POP! 在idata节的446000处,有一个写入被截停
我们处于这段代码:
Break due to BPMB #017F:00446000 W DR3
0177:00C0268F F3A5 REPZ MOVSD <-- 这
0177:00C02691 89C1 MOV ECX,EAX
0177:00C02693 83E103 AND ECX,03
0177:00C02696 F3A4 REPZ MOVSB <-- 复制剩下的区域
0177:00C02698 5F POP EDI
0177:00C02699 5E POP ESI
0177:00C0269A C3 RET
我们继续用F10追踪,直到为了复制所有的字节到idata节的第2个movsb执行时..
迅速的看一眼数据窗口,我们能看到有点象样的一个image import descriptor .
我们还是让窗口下滚,来流览一下输入表直到函数名的结尾,我们训练有素的眼睛用几秒钟告诉我们一切顺利.
在idata节只有一层压缩, (108.3版本只也有一层)。 然而它令人惊讶的是,它的创作者本来预备了几层压缩的可能性,却只用了一层!
现在,我们来DUMP内存的446000到448000 (2000个字节的Virtual Size)
要是您使用IceDump,可以跳到第二步(手动DUMP程序),要是您借助Procdump,要先用以下步骤“冻结” Aspack:
A EIP 从此处开始让程序循环在同一指示
0177:00C02698 jmp eip
然后X或F5
然后借助Procdump,在现行程序列里,选取aspack,点击鼠标右键,从446000开始,DUMP 2000个字节.保存为“ImpData_Aspk.dmp” (举例). 你不忘记 KILL TASK Aspack.
(存盘的文件符合我们在这篇文章里用的例子,Borland类型的输入表细节和视觉辨认的图表)
该转到第二步了.
第二步 : 手动DUMP出被解压程序,在它被执行前.
当然,为了这样做,要弄清aspack在哪里完成它的工作,且把任务交给被解压的程序,我不会详细解释这个过程,因为在写这篇文章时, 已经能找到一些关于Aspack2000的文章.
我将快速介绍我在这种情况下的一种特殊的方法,一种“视觉”技术(我得承认这种方法有点“野性”):
我们重启动Aspack2000.exe,在“bpm 446000 W”依然有效的情况下,我们将获得一个对idata节的写入的截断,这是我们的出发点。
我们用F10快速跟踪,无须去弄懂被执行的代码,只是数着按的次数,和观察代码所构成的图像,直到Aspack启动为止。
(相对来说很快,因为剩下没有多少要被解压的节)
重新运行Aspack,截取,快速按F10 N次,跟踪到最后一个调用程序的CALL.
一旦发现这个CALL,( 对我是 0177:00C1151F )
0177:00C1151F E874F9FFFF CALL 00C10E98 <-- 启动 Aspack2000
0177:00C11524 5F POP EDI
0177:00C11525 5E POP ESI
0177:00C11526 5B POP EBX
0177:00C11527 59 POP ECX
0177:00C11528 59 POP ECX
0177:00C11529 5D POP EBP
0177:00C1152A C20400 RET 0004
il suffit de tracer avec F8 pour arriver ici :
0177:00C10E98 89C4 MOV ESP,EAX
0177:00C10E9A 89D0 MOV EAX,EDX
0177:00C10E9C 8B1D6C66C100 MOV EBX,[00C1666C]
0177:00C10EA2 89041C MOV [EBX+ESP],EAX
0177:00C10EA5 61 POPAD <-- 恢复 registres
0177:00C10EA6 50 PUSH EAX <-- push entry point
0177:00C10EA7 C3 RET <-- call entry point
我不再详细讲,这已经见过的了.
? 89 04 1C 61 50 C3 ?字串可被看做Aspack 2000的签名.
再之,为了快速的找到这个地址,您只要执行‘s 0 L ffffffff 89,04,1C,61,50,C3’’, 在idata节开头第一个因BPM W的截断.这个搜寻能指出这些代码的所在处,现在剩下的就是在最后的RET放一个BPX,为了手动DUMP出程序.
当然,您会注意到这个技术包含一个很大的瑕疵: 它只是在代码上快的“飞行”,因而我们没有学到什么…
让我们回归主题:
让程序运行到RET,记下与程序入口处的相符的registre EAX (我的是0044295C)
象上次一样:
A EIP 从这开始修改成循环在同一指令里.
0177:00C10EA7 jmp eip
用‘BD*’来消除所有的断点.
然后X 或 F5
最后使用Procdump (总是它),选择aspack的运行程序,点击鼠标右键来个DUMP FULL.
注意:
在DUMP前,我建议您修改以下选择:
- recompute object (yes)
- optimize (no) 为了取得raw offset = virtual offset (后来的就比较容易)
- rebuild Import table 或 don’t rebuild import table ?这个选项不是太重要,反正会被我们DUMP出的文件覆盖.
将DUMP FULL 存盘为:Aspack2000_upk.exe,然后kill dask.
我们可以做第三步了.
第三步:将我们DUMP出的输入表插入已脱壳的程序中.
我们有一个脱壳后的执行程序,但它的IDATA节还没被修复好.
现在您对输入表比较了解一点了,您可以用Hexworks打开执行文件,您会发现其中的不妥之处...是的,一眼看上去,这个表好像没什么不对,但只要我们细看,真的不妥.
输入表里有些地址与别的不同, 有些指针不是指向函数的名字,而是指向00C3xxxx (即在我们的区域之外)。
这些是关于USER32.DLL和KERNEL32.DLL的函数.
如果您选择rebuid import table的选项,这些指针其中一些将是正确的.
要是您想知道,是谁,什么时候,怎么样做出来的,只要在通入IDATA的BREAK之后,来个BPR 446000 447FFF W然后重新执行,等待那个关键的BREAK,再继续跟踪,就会明白所发生的情况.
在Hexworks30 :
-打开DUMP出的“ImpData_Aspk.dmp”文件,及脱壳后的“Aspack2000_upk.exe”文件
-来个Edit /goto 46000,为了将您带到idata节的的第1个字节。
-选择那个块,大小= 2000字节(十六进制),然后删除.
-在“ImpData_Aspk.dmp”文件里重复同一步骤,选择2000个字节的块,然后“复制”
-激活“Aspack2000_upk.exe”的窗口,然后“粘贴”。
现在我们有一个脱壳后的Aspack2000的程序,并且它具有一个干净的输入表,就象它原来的一样.
剩下的一个手续就是把PE header 和 PE directory的值修改.
第四步: 将入口处及 directory Import table的地址修改升级.
用Procdump :
・ 更新被解压后程序的入口处
我的是 : 0044295C - 00400000 = 0004295C (在 eax 里显示的值- image base)
・ 修改 .CODE 节的属性为 ? E0…..20 ? 以便在 Wdasm下得到可编译代码.
・ 修改 Directory Import Table 里 的值,为了指向image import descriptor 的开头= 46000
・ 修改 size = 012C (为得到它的值,只要看看 dump出的文件,和辨认出image import descriptor的结尾.)
如果您在途中没有出错,您现在不仅有一个DUMP出的程序,而且反编译后,它的输入表是正确的,这个程序能运行.
对SoftIce的监测不再存在,因为这个被Aspack装载器收拾了…
现在,您修改好这个程序的BUG,您可以支付一个豪华的享受:也就是再用回Aspack来把脱壳后的程序重新加壳!
好了,我希望这篇文章能为大家搞清输入表带来帮助.
向那些将他们的知识,经验,技术,及工具贡献于破解的人们致谢.