译者说:
1.声明:我翻译的所有文章仅限于翻译,没有其它目的.
       一切其它用途及目的造成的后果由使用者自负.
2.来源:http://www.exetools.com/forum/showthread.php?t=8919
3.作者:DappA

 

基本信息:
壳:Armadillo 4.40 CopyMem-II, IAT Elimination, Strategic Code Splicing
   MemoryPatch protection,Custom Build
目标:dUP2.10 patcher
工具:OllyDbg1.10,HideOD,PUPE,一些需要的ollyscripts
难度:6/10

扫描目标:

最新PEID可以扫描出最新的Armadillo,扫描后得到:

 

设置"异常"

打开程序前,我们需要进一步设置"异常"



一.解决CopyMemII和DebugBlocker

进入正题.
这部分有些枯燥,如果想跳过,可以使用"DetachFarther_MethodTenketsu_hipu
_benina.txt".
我将会解释怎样手动解决.我们进入:



现在"bp WaitForDebugEvent"



由于内存补丁保护是开启的,Armadillo将会检测我们的断点是否下在API的头5个字节上.
因此我们需要把断点移向API5个字节后或使用内存断点.我使用后者.



我不会每次都用图,而会用文字说明代替.
断点下好后,运行一下.经过一些非API的地方后,我们来到:



保存以下信息:
0012DC64 00431D86 /CALL to WaitForDebugEvent from test.00431D80
0012DC68 0012ED54 |pDebugEvent = 0012ED54
0012DC6C 000003E8 \Timeout = 1000. ms

CTRL+F2重起程序,在WriteProcessMemory上下新的断点.SHIFT+F9运行直到看到
1000字节转换为止.



注意BytesToWrite==1000.这里是我们首个CopyMem crypttransfer.也保存一下

0012DB04 00435D57 /CALL to WriteProcessMemory from test.00435D51
0012DB08 00000048 |hProcess = 00000048 (window)
0012DB0C 00401000 |Address = 401000
0012DB10 003A3988 |Buffer = 003A3988
0012DB14 00001000 |BytesToWrite = 1000 (4096.)
0012DB18 0012DC20 \pBytesWritten = 0012DC20

在同一个窗口中,下滚知道发现主程序返回.你还会发现有个小循环:



我把它粘贴到这里:0012DC2C |004349C5 RETURN to test.004349C5 from test.00434D0D
这部分很重要,它将会带领我们到达用来控制CopyMem函数的cryptocall中.



CTRL+G前往表达.你会来到PUSH EBP指令.选中它,CTRL+R得到所有关于此指令的
参考.



双击第二个CALL,你会来到此CALL.NOP掉它.



很好.现在你将去找子进程的OEP.CTRL+F9,F8退出WriteProcessMemory,DUMP窗口中CTRL+G,键入pDebugEvent地址:0012ED54



第一行,子进程OEP为00401FAA.我们稍后会需要这三个地址.

0012ED6C 00401FAA test.00401FAA (OEP) 
0012ED70 00000002
0012ED74 00000000
0012ED78 00401FAA test.00401FAA
0012ED7C 00401FAA test.00401FAA

修改子进程为无限循环

现在我们将修改OEP处的子进程为无限循环.打开PUPE,打开程序(记得使用正确
的进程),键入OEP.



记下原字节:8D 9B
修改它.

关闭PUPE.回到Olly,在WaitForDebugEvent上设置内存断点.中断后,前往正确的
dump节并"反汇编跟随":0012DC64 00431D86 /CALL to WaitForDebugEvent from test.00431D80
在CPU窗口中NOP掉WaitForDebugEvent,在"TEST EAX,EAX"选上择"新的起源":



现在你将会跳到.text节,你可以写下自己的代码:



走至JMP,回车.这就是我们将会用一些代码处理CopyMemII和DebugBlocker的地方.
添加以下内容:

0040103C 8105 6CED1200 00100000 ADD DWORD PTR DS:[12ED6C],1000
00401046 8105 78ED1200 00100000 ADD DWORD PTR DS:[12ED78],1000
00401050 8105 7CED1200 00100000 ADD DWORD PTR DS:[12ED7C],1000
0040105A 813D 7CED1200 00104000 CMP DWORD PTR DS:[12ED7C],00401000
00401064 ^ 74 D6 JE SHORT 00401000
00401066 813D 7CED1200 00304000 CMP DWORD PTR DS:[12ED7C],00403000
00401070 - 0F85 150D0300 JNZ 00431D8D
00401076 68 400B0000 PUSH 0B40 (PID!) 
0040107B E8 1193457C CALL DebugActiveProcessStop
00401080 90 NOP

我来解释一下.记得先前的3行吗?

0012ED6C 00401FAA test.00401FAA
0012ED70 00000002 
0012ED74 00000000 
0012ED78 00401FAA test.00401FAA
0012ED7C 00401FAA test.00401FAA

因此我们添加了1000字节到这三个地址,接着用最后的地址与.text节的401000
进行比较.相等则重新执行直到完成.
接下来比较.rdata节.非0则跳回"JMP 401000"下的NOP.

首先修正指针:



在最后的NOP上设置断点,SHIFT+F9运行:



现在添加子进程,运行,暂停(SHIFT+F9,F12).把无限循环改回原代码:8D 9B



祝贺你,你现在得到了"干净"的OEP.我们解决了CopyMemII和DebugBlocker.不要关闭.下面我们解决IAT重定向,IAT Elimination和Code Splicing.

二.输入表重定向和Elimination+Spliced Code
现在探讨重定向部分.
Armadillo的IAT重定向有一张重定向表,它被用来抽取原代码,以自己的方式来处理.
我们的目标就是阻止Armadillo重定向任何API.

首先,我们需要找一个当前进程的API.进入第一个CALL,查找API.任选一个.我选择了以下:
00402AAE - FF25 980BD800 JMP DWORD PTR DS:[D80B98] ; GDI32.SetTextColor

DUMP窗口中跟随地址.修改"查看"为"长型地址".你可以看到许多API,上滚至IAT
表头:



00000000表示开始.现在下滚至:



现在我们打开新的Armadillo程序.我们不需要干净的代码,只要干净的IAT就可以了.我们将修正IAT重定向.
运行,暂停,修改字节.就这样做.

SHIFT+F9运行,直到Privileged Instruction异常停止.
bp VirtualProtect,运行,中断.CTRL+F9,退出API.你到达了Armadillo代码中.
CTRL+F查找命令PUSH 100.来到PUSH EBP.修改为RET.



搞定IAT重定向.运行直到OEP.很简单.
bp CreateThread,SHIFT+F9,CTRL+F9,F8,下滚直到CALL ECX,bp,F7进入.

到达OEP.但我们需要的是干净的IAT.得到先前API的16进制代码:



ALT+M打开内存镜像,查找二进制.记得选中头地址,查找整个镜像.



这就是完成的过程.现在我们要做的就是复制整个新的IAT到已损坏的IAT中.



回到OEP,你会看见GetCommandLineA, 之前是没有的,因为壳把它重定向到自己的代码中了.

现在我们用ArmInline修正spliced code和IAT elimination.很简单.我们先找到spliced code.进入修正的IAT进程的第二个CALL中.发现00402BF9 - E9 12E4C001 JMP 02011010
它前往高内存地址,因此它就是spliced code.

ALT+M打开内存镜像,查找分配的部分:



spliced部分往往在分配地址的底部.在每次重起程序时,分配地址是任意的,这是因为壳通过经时间API的任意函数分配地址.打开ArmInline,填入以下数据:



目标代码开始于.text节,长度为.text节的长度.选择"remove Splices".解决!
下面是IAT Elimination:



00D809CC - IAT START
00D80D20 - IAT END
IAT SIZE: 354

新的RVA基地址在.adata节中,分配给00455000.
我们现在用LordPE来dump目标程序.完成后,打开ImportREC重建IAT.使用当前的
OEP,IAT大小前面有,"cut thunk(s)",添加IAT到dumped.exe中.试试.正确运行!




DappA

感谢:Hacnho的精彩教程和视频,向这些不错的工具,Tenketsu和Ricardo写的一些
Ollystripts致敬.

鸣谢:ICU,TSRH,SND,ARTEAM和MP2K[U]