首页
社区
课程
招聘
[翻译]Armadillo 4.30a 最少保护下的脱壳教程(请删)
发表于: 2006-1-13 11:56 4724

[翻译]Armadillo 4.30a 最少保护下的脱壳教程(请删)

2006-1-13 11:56
4724
=================================================================
  [翻译]Armadillo 4.30a ? 最少保护下的脱壳教程
=================================================================
译者说:
目的:学习研究,技术交流,禁止用于商业用途及目的,否则后果自负.
作者:haggar
1.        准备工作

你需要以下工具理解此教程:
目标:http://www.reversing.be/binaries/articles/2005092823071234.rar
Windows XP
OllyDbg1.10
ImpREC
LordPE
PEID0.93(可选)

脱Armadillo最小保护的程序很简单,而且这一类型的程序可以在网上找到。我不明白为什么开发者不使用所有的选项,可能当程序要维持一些如注册表清洁、碎片整理等等功能时,双进程会减缓目标程序的运行。不管怎样,现在我们需要解决以下问题:

Olly OutputDebugStringA的使用;
锁文件的PE文件头修改;
输入表重定向和修改。

2.        到达OEP

首先Olly选项忽略所有异常。在Olly中打开目标程序,(右键)单击“前往”->“表达”,输入VirtualAlloc,确定。你会来到Kernel中的VirtualAlloc:

77E7ABC5  PUSH EBP <--------------------- VirtualAlloc的开始语句
77E7ABC6  MOV EBP,ESP
77E7ABC8  PUSH DWORD PTR SS:[EBP+14]
77E7ABCB  PUSH DWORD PTR SS:[EBP+10]
77E7ABCE  PUSH DWORD PTR SS:[EBP+C]
77E7ABD1  PUSH DWORD PTR SS:[EBP+8]
77E7ABD4  PUSH -1
77E7ABD6  CALL kernel32.VirtualAllocEx
77E7ABDB  POP EBP
77E7ABDC  RETN 10 <---------------------- 此处(F2)下断Amadillo不会发现。

为什么要这样做?(因为)我们需要找到Armadillo在哪里解压和装载自身DLL。中断时,EAX寄存器将会保存内存块分配的基址,那是DLL将被解压的地方。F9中断第一次后EAX=0。再F9一次,EAX将保存一些值。在我的机器上EAX=00AA0000,你机器上的值可能会不同。现在清除断点,在命令栏中“bp OutputDebugStringA”。F9一次,你会来到这里:

77E9B493  PUSH 22C <------------------------ 来到这里(22C值可能也会不同)
77E9B498  PUSH kernel32.77E9BE60
77E9B49D  CALL kernel32.77E7A22B
...
...
...
77E9B4CB  CALL kernel32.RaiseException
77E9B4D0  OR DWORD PTR SS:[EBP-4],FFFFFFFF
77E9B4D4  CALL kernel32.77E7A2F2
77E9B4D9  RETN 4

这里是Armadillo准备崩溃Olly的地方。Olly不支持%s%s...(寄存器窗口中可以看到此值)字符串因此崩溃。我们需要去除此校验。这不难,只要把API的第一个操作数改为最后的(返回)语句即可。因此,(我们)清除断点,RETN 4替换PUSH 22C:

77E9B493  RETN 4 <-------------------------- 修改后
77E9B496  NOP
77E9B497  NOP
77E9B498  PUSH kernel32.77E9BE60
...
...
...
77E9B4CB  CALL kernel32.RaiseException
77E9B4D0  OR DWORD PTR SS:[EBP-4],FFFFFFFF
77E9B4D4  CALL kernel32.77E7A2F2
77E9B4D9  RETN 4

现在“bp CreateThread”,(F9)运行Olly。你会中断在Kernel的CreateThread中(是在NAG窗口出现以后)(NAG窗口之后很重要,之前的中断不是),清除断点,ALT+F9返回主程序中:

00AB94C4  POP EDI <----- 来到这里
00AB94C5  POP ESI
00AB94C6  LEAVE
00AB94C7  RETN <-------- F7跟踪执行此RET

退出RET后你会来到:

00AC972D  POP ECX
00AC972E  MOV EDI,0AD8910
00AC9733  MOV ECX,EDI
...
...
...
00AC97ED  CALL ECX
00AC97EF  JMP SHORT 00AC9814
00AC97F1  CMP EDX,1
00AC97F4  JNZ SHORT 00AC9817
00AC97F6  PUSH DWORD PTR DS:[ESI+4]
00AC97F9  MOV EDX,DWORD PTR DS:[EAX+88]
00AC97FF  XOR EDX,DWORD PTR DS:[EAX+84]
00AC9805  PUSH DWORD PTR DS:[ESI+8]
00AC9808  XOR EDX,DWORD PTR DS:[EAX+40]
00AC980B  PUSH 0
00AC980D  PUSH DWORD PTR DS:[ESI+C]
00AC9810  SUB ECX,EDX
00AC9812  CALL ECX <----------------------- 跳向OEP
00AC9814  MOV DWORD PTR SS:[EBP-4],EAX
00AC9817  MOV EAX,DWORD PTR SS:[EBP-4]
00AC981A  POP EDI
00AC981B  POP ESI
00AC981C  LEAVE
00AC981D  RETN

你看到最后的那个CALL ECX了吗?那是跳向OEP的(CALL)。在3.xx版本之前,这里是CALL EDI而不是CALL ECX,但(现在)Armadillo开发者修改了(这里)。他修改了一些小处以阻止一般的脱壳机和Olly scripts(脱壳)。这是别人告诉我的,事实也确是如此。上述CALL是跳向OEP的,因此执行它后你会来到OEP处(1。此CALL前有一跳转,跳则不能到达,需要修改。2。执行=F7进入)。

004013FB  PUSH EBP <--------------------- OEP
004013FC  MOV EBP,ESP
004013FE  PUSH -1
00401400  PUSH Armadill.004040B8
00401405  PUSH Armadill.00401F30
0040140A  MOV EAX,DWORD PTR FS:[0]
00401410  PUSH EAX
00401411  MOV DWORD PTR FS:[0],ESP
00401418  SUB ESP,58
0040141B  PUSH EBX
0040141C  PUSH ESI
0040141D  PUSH EDI
0040141E  MOV DWORD PTR SS:[EBP-18],ESP
00401421  CALL DWORD PTR DS:[40402C] <----- 这里是一些输入表
00401427  XOR EDX,EDX
00401429  MOV DL,AH
...
...
...

这时你找到了OEP,但是如果你现在DUMP文件,它将是坏的和锁定的,因为Armadillo修改了PE header的三个值。另外还有Stolen输入表的问题。

3.        PE文件头问题

如果你打开内存镜象,你会发现PE文件头是坏的,Olly无法识别:

00400000   00001000   Armadill                            Imag   R         RWE <--- PE头
00401000   00003000   Armadill   .text                    Imag   R         RWE
00404000   00001000   Armadill   .rdata                   Imag   R         RWE
00405000   00001000   Armadill   .data                    Imag   R         RWE
00406000   00050000   Armadill   .text1     code          Imag   R         RWE
00456000   00010000   Armadill   .adata                   Imag   R         RWE
00466000   00020000   Armadill   .data1     data,imports  Imag   R         RWE
00486000   00030000   Armadill   .pdata                   Imag   R         RWE
004B6000   00002000   Armadill   .rsrc      resources     Imag   R         RWE

Armadillo删除的3个值分别是:DOS头中的PE头偏移,PE头中的节数量和程序入口点。修正方法就是打开另一个Olly,打开目标文件,二进制复制(ALT+M->PE部分双击->全选->右键->二进制->二进制复制。粘贴同)整个PE头并粘贴到这里。现在你可以用LordPE DUMP文件了,但是在ImpREC中有一些未解决的thunks,我这里是16个。跟踪级别1得到的是错误的输入表因此不能依赖它。

4.        IAT问题

Rdata节是保存输入表thunks的。去看看(在你到达OEP的后),你会发现一些值是错的:

00404020  FF 7E AB 00 7E 17 E6 77 AF 81 AB 00 A3 81 AB 00  .~..~..w........
00404030  D6 69 AB 00 99 6A AB 00 0C E6 E7 77 95 9B E9 77  .i...j.....w...w
00404040  FC AC E7 77 2F E0 E9 77 E8 E4 E7 77 9C A8 E7 77  ...w/..w...w...w

例如,上面节选中的首个值FF7EAB00不是输入表的值。下个值是正确的:7E17E677。你会发现,首个值指向ArmDLL。我们需要找到IAT在哪儿被重定向并阻止它。Olly中重起目标程序,修正OutputDebugStringA问题,在00404020处下硬件写入双字断点(数据窗口->前往->表达->00404020选中->右键->断点->硬件写入->双字)。F9一次后(在OutputDebugStringA问题后)(要经常清除断点),你会中断如下:

77C42F43  REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
77C42F45  JMP DWORD PTR DS:[EDX*4+77C43058]        ; MSVCRT.77C43068
77C42F4C  MOV EAX,EDI                              ; Armadill.00404024
77C42F4E  MOV EDX,3
77C42F53  SUB ECX,4
77C42F56  JB SHORT MSVCRT.77C42F64
77C42F58  AND EAX,3
77C42F5B  ADD ECX,EAX
77C42F5D  JMP DWORD PTR DS:[EAX*4+77C42F70]
77C42F64  JMP DWORD PTR DS:[ECX*4+77C43068]
77C42F6B  NOP
77C42F6C  JMP DWORD PTR DS:[ECX*4+77C42FEC]
...
...

这是第一次中断,它并不重要。F9第二次,你来到了重点:

00AC6979  CMP DWORD PTR DS:[EAX+8],0 <-------------- 比较列表中的所有API是否都已校验
00AC697D  JE SHORT 00AC69C8
00AC697F  PUSH 100
00AC6984  LEA EAX,DWORD PTR SS:[EBP-3BF4]
00AC698A  PUSH EAX
00AC698B  MOV EAX,DWORD PTR SS:[EBP-3AF4]
00AC6991  PUSH DWORD PTR DS:[EAX]
00AC6993  CALL 00ACCF05
00AC6998  ADD ESP,0C
00AC699B  LEA EAX,DWORD PTR SS:[EBP-3BF4]
00AC69A1  PUSH EAX
00AC69A2  LEA EAX,DWORD PTR SS:[EBP-3AE4]
00AC69A8  PUSH EAX
00AC69A9  CALL DWORD PTR DS:[ACE384] ; MSVCRT._stricmp <--- [3] 比较API名
00AC69AF  POP ECX
00AC69B0  POP ECX
00AC69B1  TEST EAX,EAX
00AC69B3  JNZ SHORT 00AC69C6 <--------------- [4]如果API在列表中,则不跳转
00AC69B5  MOV EAX,DWORD PTR SS:[EBP-3AF4]
00AC69BB  MOV EAX,DWORD PTR DS:[EAX+8]
00AC69BE  MOV DWORD PTR SS:[EBP-32E4],EAX
00AC69C4  JMP SHORT 00AC69C8
00AC69C6  JMP SHORT 00AC6964
00AC69C8  MOV EAX,DWORD PTR SS:[EBP-28A4]
...
...
...
00AC6B64  MOV DWORD PTR DS:[EAX],ECX <--------- [2] 这里是值写入的地方。
00AC6B66  MOV EAX,DWORD PTR SS:[EBP-24EC] <---- [1] 中断在这里

我们到达了重定向值写入的地方,但是可惜的是我们远离了大段的代码。主要部分在[5],Armadillo用来比较自身列表中的所有API名。如果API在列表中,跳转[4]不实现,API被修改。这就是我们用来对付API重定向的地方。跳转[5]只是比较是否所有的API名都取完。因此我们只要修改跳转[4]的JNZ为JMP即可。但是现在已经晚了,因为大多数的输入表已经被重定向。我们记住跳转地址,在我的电脑上是00AC69B3。写下这个数据,重新开始。

Olly中重起目标,修正Olly检测。在CPU窗口中选择“前往”->“表达”,输入跳转地址,我的是00AC69B3,来到:

00AC69B3  JNZ SHORT 00AC69C6
...
...

到达跳转。很好。现在修改为JMP。接着,“bp CreateThread”,到达OEP。打开ImpREC,(get imports)得到输入表,单击“(show invalid)显示无效”,(cut)切除所有的无效thunks,(Fix dump)修正dump,运行一下,成功。

5.        优化文件

添加到加壳程序的Armadillo代码很大。加壳文件520kb,脱壳文件740kb。我们可以使用LordPE精简。使用LordPE的PE编辑器(PE editor)打开脱壳文件。首先修改BaseOfCode的6000为1000,BaseOfData的66000为5000。接着打开“节”选项。你会看到Armadillo添加了:.text1,.adata,.data1和.pdata。右键单击上述节,选择“擦除节头(wipe section header)”。“关闭”节表。“保存”修改。打开LordPE“选项”,选中(“DumpFix”,“Realign file…->hardcore”)“dump修正”,“重分配文件为…->核心”以及(“validate PE”)“使PE有效”。现在(“rebuilder”)“重组”脱壳文件,文件大小精简到原来的2%->22kb。

6.        总结

教程并不难,练习了最少保护下的Armadillo。下篇教程是关于Armadillo一般保护的。基本是同最少保护的,不同的是有一些包含阻止内存断点的加密和CRC校验而已。

感谢所有来到BIW reversing的同行们。

[课程]Android-CTF解题方法汇总!

收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 898
活跃值: (4039)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
2
翻译辛苦
教程方法不妥
2006-1-13 12:09
0
雪    币: 1170
活跃值: (3622)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
3
确实有问题,版主删除此贴吧,以免误人子弟.
2006-1-13 13:51
0
雪    币: 427
活跃值: (412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
www.reversing.be
这个网一向以初学者入门为主,让初学者能举一反三
2006-1-13 14:11
0
游客
登录 | 注册 方可回帖
返回
//