ESP法和二次断点法脱壳总结

来源:互联网 发布:淘宝深夜食堂视频全集 编辑:程序博客网 时间:2024/05/01 08:42

ESP法和二次断点法脱壳总结

一直想学一些逆向破解之类的知识,但是起步比较难,听看雪的某个高手说你可以从免杀方面的知识入手,掌握点基础。

首先感谢姬良写的《杀不死的秘密》这本书,真心不错。

1、ESP

原理:维持堆栈平衡

壳程序运行后,首先运行壳部分,然后将原程序还原到内存中并将控制权返还。而大部分压缩壳在运行壳程序时都会将原程序做一个堆栈保护,壳程序运行完成后将原程序还原到内存时会将原先保存的环境恢复供原程序使用,这样我们就可以很轻易的找到OEP。

操作实践:

未加壳程序text.exe

入口点:00001020



加UPX壳程序UPX壳.exe


入口点:0000A7B0

同时也提示加了UPX壳,说明加壳成功。


载入OD(OllyICE),出现下面提示,选择否。


程序停在0040A7B0处,这里有一指令 


pushad 这一指令很重要,他的作用是将所有32位寄存器压栈,很显然这是为了保护环境。如果这条指令后面有JMP指令,

那么JMP指令后的地址很可能就是OEP

在看一下寄存器部分注意和下面对比。


F8单步调试


发现ESP变了,EIP为指令寄存器不管它,在下面的Command编辑框中输入

Hr 0012FFA4 在按回车键,在这里下一个硬件中断。F9直接运行。


程序停在Jmp这里 ,在看下图有没有发现寄存器的值和执行pushad指令前一样,这就说明在这里做了环境恢复。

F7调试步入。


这时程序停在00401020出,这时你会觉得很熟悉了,原程序入口点是00001020,这里的00401020是基址00400000加上入口点得到的虚拟地址。既然找到了原程序的入口点了,接下来就是脱壳了。

右击00401020处指令选择Dump debugged process


点击 Dump按钮保存即可,之后我们运行脱壳后的程序,并用Pedit查看和加壳前的程序比较。发现是一样的,说明此次脱壳成功。


总结:改方法脱壳利用堆栈平衡原理,适用于大部分压缩壳,方法简单。但在脱北斗壳是会出现一些假象,不要管他继续Dump即可。


2、二次断点法(又叫内存镜像法)

个人觉得这个原理比较难懂一点,需要一点PE结构的知识。我对这方面原理的理解来自

看雪论坛http://bbs.pediy.com/showthread.php?t=20366 

黑客防线http://bbs.hackerxfiles.net/archiver/tid-88027.html 

原理:(较长,重要部分已做了标注)

首先,在OD中内存断点,硬件断点和普通断点(F2下断)是有本质区别的。硬件断点等效与SoftICE命令bpm,他的中断要用到DR0-DR7的调试寄存器,也就是说OD通过这些DR0-DR7的调试寄存器来判断是否断下。

    普通断点(F2下断)等效于bpx,他是在所执行的的代码的当前地址的一个字节修改为CCint3)。当程序运行到int3的时候就会产生一个异常,而这个异常将交给OD处理,把这个异常的regEIP-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.内存执行的地方,也可以用内存访问中断。

  总结一下:内存断点不修改改原代码,不会像普通断点那样因为修改代码被程序校验而导致中断失败;对于区段的访问只是区域大了一点,其原理和上面分析的三行代码是一样的。

  壳如果要把原来加密或压缩的代码运行起来就必须要解压和解密原来的代码。而这一个过程我们难道不能将他看做是对代码段(code段)的写入吗?好了,解压完毕了。我们要从壳代码的区段JMP到原来的代码段的时候,难道不正是对代码段(code段)的执行吗?

  理清了上面的关系就好办了,那么如果载入OD后,我们直接对code段下内存访问断点的时候,一定会中断在壳对code段的写入的代码的上面,就像上面的004AE247的这一行。而如果当他把code段的代码全部解压解密完毕了以后,JMPOEP的时候,我们是不是还可以停在OEP的代码上面呢?而且每按下F9都会中断,因为这时code段在执行中哦!

  让我来做一个假设吧,假设我是一个壳的作者。一个EXE文件的有code段,data段,rsrc.....依次排列在你的内存空间中,那么我会怎么解码呢?呵呵~我比较笨一点,我会先将code段解码,然后再将data段解压,接着是rsrc......那么聪明的你不难发现,只要你在data断或者rsrc段下内存访问断点,那么中断的时候code段就已经解压完毕了。这时我们再对code段下内存反问断点,不就可以到达OEP了吗?

  这里注意上面虽然下了两次内存访问断点,但是本质是不一样的,目的也是不一样的。

  1.data段下内存访问断点而中断是因为内存写入中断,目的是断在对data段的解压时,这时壳要对data段写数据,但是code段已经解压完毕。

  2.code段下内存访问断点而中断是因为内存执行中断,目的当然就是寻找OEP了。

  总结一下:如果我们知道壳在什么地方对code段解压完毕我们就可以使用内存断点,找到OEP。如果不知道,那么我们就依靠2次内存断点去找,如果还不行就用多次内存断点。总之明白了原理在多次的内存断点其实都一样。从这个过程中我们了解的是壳在对区段解码的顺序!

实践:对ASP壳加壳的程序脱壳

原程序:


加壳后的:


将加壳后的程序拖到OD中。这时要在OD中进行一些设置,选项---调试设置

在调试设置对话框中单击所有的异常复选框,也就是忽略所有的异常选项,然后重新载入程序。是否分析,点击否,打开内存alt+m.


这里在选断点时 我测试了很多回,不知道什么原因总是不成功,按照书上说资源段设置访问断点,在shift + F9运行,然后程序就直接运行完了,没有任何停顿。难道是我的程序没有资源段吗,反正.code段是最先被解压的,这里我只要下一个断点在.code段以后就可以了,经过我的测试,越靠前越好,不会出现直接运行的情况,这里我是下载数据段.data


运行,这里还有一个问题,为什么是shift+f9运行,而不是直接运行。但经过我的测试结果是一样的。

程序停在什么地方,此时不管他,继续回到内存页面,在.code下断,在我的程序中对应的是.text段。


接着按shift+f9运行,接着程序停在如下地方:


这时你会很熟悉这个地址,不错他就是OEP了,直接Dump下来就可以了。

但是这里有一个很大的疑问,为什么我的程序二次断点就到了OEP呢,在这里我们是知道OEP的情况下才敢这么确定,如果不知道OEP的情况下,又没有恢复环境POPAD这种标志指令,怎么判断的确是个问题,书上脱壳时貌似还走了很多步才到OEP,这导致我很费解,望高手能够指导一下。

也许脱壳多了就有经验有能力判断了,看来还是得多练练。。

原创粉丝点击