FTBirthday的Armadillo全程教程--第二章copy-mem II加壳方式
第二章.copy-mem II加壳方式
[实例解析三] \\*Armadillo-手动脱变种的壳**//** 原著crUsAdEr**翻译改写FTBirthday
这篇教程的目标是讨论Armadillo 2。61的保护机制以及如何手动地脱去armadillo的保护层! 希望以此能够展示出,被越来越依赖于工具的cracker们,遗忘的手动脱壳技术的威力。
需要的工具:
OLLYDBG on Win XP
LordPE
脱壳对象: Get Right 5。0 beta 1
下载连接: GetRight5。0beta
序言
Armadillo 2。61只是附加了一些新特性,使得逆向工程变得更有趣。Armadillo调试由它自身保护的软件, 这一点使得我们这些crackers在跟踪调试目标时,遇到了很大的困难。但是好的一方面是Armadillo自身的代码并没有被以任何方式加上花指令或者加密,所以我们可以用IDA反汇编保护层,以供研究之用。
i) 这篇tutorial中的所有代码片断都是从IDA反汇编得到的,包括IAT redirection 部分,其他部分也可以在相同的地址在IDA反汇编代码中被找到,只要你获得的是相同版本的Getright。exe。
ii) 贯穿这篇essay,我以ebp+someName的形式使用变量名,以使得读者在softice中跟踪调试时易于理解,你需要键入实际值,例如"ebp+FFFFFAE0"
iii) Armadillo保护的程序开启了两个进程,保护壳调试被保护的目标,所以我有必要说明,调试器为"server" 被调试软件为"Client"
iv) 同样要注意的是IAT redirection在WIN9x平台上是不同于winNT/2k/XP的,所以这篇essay仅仅讨论IAT redirection在win2k平台,当然你可以在win9x平台上以类似的方法找到 IAT redirection routine!
(最后,请在Fravia board上阅读关于Armadillo保护的理论和方法,还要确信你已经牢固的理解了PE文件格式,因为那是重建PE映象的基础!)
使命:打败 copy-mem II
第一关.如何UNPACK以及DUMP Getright 5
好了, 我希望你已经知道什么是copy-mem II和它能做什么。下面开始标准的流程。
第一步:挫败anti-debug代码,重置检测IsDebuggerPresent API的那个字节!
用OLLYDBG载入程序.在调试选项中忽略所有异常,这样可以少按SHIFT+F9.
[方法一]
用IsDebug 1.4插件去掉Ollydbg的调试器标志。
[方法二]
Bp IsDebuggerPresent

现在按F9运行程序,当遇到异常,一直按SHIFT+F7或者F8,直到中断于

在这张图中我们可以看到OllyDBG中断在API IsDebuggerPresent(红色), 然后按F7步进到第三行(白色) 77E52749 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+2]
一旦我到达那儿,看一下disassembly,在那儿我们可以看到的内容如下图:

这儿我们可以看到在我的机器中偏移是7ffdf002,包含了值01.这个地址在其它机器中可能会不同. 值01意味着调试器被检测到了,所以写下这个地址,在任何时候我们在ollydbg中运行程序,都必须改变它为00,从而避免被packer检测到.记住改变此值为00在任何时候在ollydbg中运行或重运行程序. 记下这个地址,以后经常会用到的。
我们将以重启ollydbg (ctrl+F2)来结束第一步,到转储窗口(DUMP)单击右键选择"前往表达" 7ffdf002或者其它任何先前你记下的地址,然后改变它的值从01变为00.
第二步.找OEP,对于copy-mem II有三种方法
[方法一],BP WRITEPROCESSMEMORY(使用OLLYDBG)
BP WaitForDebugEvent,当它停下时我们可以在Stack 窗口看到关于这个API的所有参数信息。

看一下第二行。那儿我们可以看到它将在哪儿显示report,所以到dump窗口,右键选择 "前往 表达"= 12EFF8。注意这个值在一些机器上可能会不同,所以前往你的机器显示的值。

我们在上面的图中看到的是我们将要称之为"API report"的东西。父进程通过那里得知子进程发生了什么。 现在我们可以很容易地通过在命令行输入BC WaitForDebugEvent来删除这个断点。

所有的操作都是为了在dump窗口看到report,在这个report中我们可以看到入口点OEP。
Bp WriteProcessMemory正如我们在下图中看到的, 父进程将要复制给子的第一个块的所有信息,都可以在STACK窗口看到。

这些信息被保存在父进程的一个缓冲区从3B8FB0开始,然后它会复制给子进程一个从538000开始的 1000 bytes的块,所以如果我们到了这一步,我们可以很容易理解子进程的第一个section是完全空的,所以当它试图执行到OEP时,它报告一个错误因为那儿没有任何东西,所以父进程得到了通知正如我们可以在父进程的report中看到的,所以它停止了运行,复制必要的数据块,然后继续运行直到下一个错误。被复制的数据块的大小是1000 bytes,所以当程序试图执行任何超过这个大小的块外的指令时, 另一个错误将会发生,然后这个错误会被通知给父进程, 父进程会复制另外1000 bytes的块然后继续。
顺便说一下,我们可以假设第一个错误发生是因为子进程call了它的入口点OEP,它的值应该就在report上。显然OEP的值必定在第一个块,父进程复制过去来解决子进程报告的错误。
这个块从538000开始直到538fff。OEP值必定在这些值中。让我们看一下report。看dump窗口我们先前已经知道了指向report的指针12EFF8。

太好了!在那儿我们至少看到了三次这个值: 538540。数学课告诉我538540比538000大,比538fff小 (那些是父进程试图拷贝给子进程的那个块的起止值)所以我可以确信538540就是子进程的OEP。
[方法二],捕获页面保护异常、找OEP(使用OLLYDBG)
Armadillo外壳即父进程通过CreateProcessA产生另外一个进程即子进程。所以可以通过捕获页面保护异常、找OEP。
以上代码在子进程的第一条指令处写入“eb fe”代码,即“jmp eip” 使子进程被“挂起”
以上代码通过调用“DebugActiveProcess”开始调试子进程。
以上进入调试循环,根据DebugEvent结构中的debugging event code 做相应处理。其中最 重要的是EXCEPTION_DEBUG_EVENT(0x00000001)。请参考MSDN中WaitForDebugEvent的描述。
较是否是EXCEPTION_DEBUG_EVENT。(包括页面异常)
注意在NT下,页面异常的代码是0x80000001(STATUS_GUARD_PAGE_VIOLATION)而9x下是0xc0000005(STATUS_ACCESS_VIOLATION)
当子进程需要解码时,会触发页面异常,来到上述代码,如果你参考MSDN中有关 DebugEvent结构的描述,很容易找到产生页面异常的地址,是在lpDebugEvent+0x18处。(即ECX +18)。
这有什么用呢?呵呵……这是找OEP的关键!!!假如在005F75C6下断点,当程序第一次在这里中断时,查看ECX +18h的内容“dd ECX +18”即可看到OEP。
1 2 3 4 下一页