飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2992|回复: 3

[07版] ESP定律和内存断点(壳编)

[复制链接]
  • TA的每日心情
    慵懒
    2018-6-6 15:51
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2007-4-15 15:44:17 | 显示全部楼层 |阅读模式
    如有不妥之处请指正~

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?加入我们

    x
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2007-4-15 16:38:48 | 显示全部楼层
    看完了 兄弟写的够详细 支持下~~ /:01
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2016-4-11 20:07
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2007-4-23 20:54:01 | 显示全部楼层

    为了重新解决转贴格式的问题,我把文章贴出了

    【文章标题】: ESP定律及内存断点

    【文章作者】: glts

    【作者邮箱】: glts@163.com

    【本文例子】: ASPACK.98记事本

    【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

      一、ESP定律

      EQ:何为ESP定律;为什么我们在脱壳的时候在程序载入OD后F8单步对寄存器ESP值地址下硬件断点后会来到壳跳向程序OEP的地方?

      AS:ESP定律就是“堆栈平衡”原理也就是壳入栈和出栈的地址为对应

    我们来看下面的图:

    ―――――――――――――――――――――――――――――――――――――――

    程序载入OD时CPU主线程:


    寄存器:


    堆  栈:


    当我们F8单步后的图:

    CPU主线程:


    寄存器:


    此时的堆栈和寄存器的对比图:


    ―――――――――――――――――――――――――――――――――――――

    通过此图大家可以看出壳在压栈也就是把寄存器的值全部压入堆栈,那么即然是“堆栈平衡”原理,在壳的出口也就是将要到达OEP时的值也应该是一样的,再看下图是程序将要到达OEP图:


    和加壳程序载入OD的堆栈图比较一下大家就明白了:


    除了EIP不同以外,eax保存当前OEP值,其他都样。
    为什么会这样呢?我们来看看
    A:PUSHAD



    B:CALL



    C:popad




    D:JNZ



    ――――――――――――――――――――――――――――――――――――――
    0040D000 A>  60               pushad  //注意这里ESP=0012FFC4(壳入口)
    0040D001     E8 00000000      call ASPACK.0040D006  //ESP=0012FFA4

    PUSHAD就是把所有寄存器压栈!我们在到壳的最后看看:

    0040D558     61               popad  //ESP=0012FFA4(壳出栈口)
    0040D559     75 08            jnz short ASPACK.0040D563 //注意这里ESP=0012FFC4
    ―――――――――――――――――――――――――――――――――――――――
    现在大家可以看出什么来了吧……两两对应。
    ―――――――――――――――――――――――――――――――――――――――
    也就是说当我们对ESP的0012FFA4下硬件访问断点之后。当程序要通过堆栈访问这些值
    ,从而恢复原来寄存器的值,准备跳向OEP的时候,OD帮助我们中断下来。
    我们可以把壳假设为一个子程序,当壳把代码解压前和解压后,他必须要做的是遵循堆栈平衡的原理。那怕就是有些壳偷代码抽取字节表面是不遵循堆栈平衡的原理实际上还是遵循的,也有的不把值放在ESP中而是放在了其它的地方,以防止ESP定律脱壳。

    因为大家对ESP理解各有异同,但是,大同小异!一般理解可以为:
    1、在命令行下断hr esp-4(此时的ESP就是OD载入后当前显示的值)
    如果在载入OD后的pushad时的(ESP值-4)值,此例为(0012FFC4-4=0012FFC0)下断运行断下的地方刚好就是POPAD出栈。
    2、hr ESP(关键标志下一行代码所指示的ESP值(F8单步通过))
    3.是不是只能下断12FFA4的访问断点?
    当然不是,那只是ESP定律的一个体现,我们运用的是ESP定律的原理,而不应该是他的具体数值,不能说12FFA4,或者12FFC0就是ESP定律,他们只是ESP定律的一个应用罢了!
    ―――――――――――――――――――――――――――――――――――――――

    内存断点

    ―――――――――――――――――――――――――――――――――――――――

       1.什么是内存断点?

       2.如何在寻找OEP时使用内存断点。  

    3、内存断点寻找OEP的原理

    A.首先,在OD中内存断点和普通断点(F2下断)是有本质区别的。

    内存断点等效于命令bpm,他的中断要用到DR0-DR7的调试寄存器,也就是说OD通过这些DR0-DR7的调试寄存器来判断是否断下普通断点(F2下断)等效于bpx,他是在所执行的代码的当前地址的一个字节修改为CC(int3)。当程序运行到int3的时候就会产生一个异常,而这个异常将交给OD处理,把这个异常给EIP-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.内存执行的地方,也可以用内存访问中断。



    如果这时你认为,那么内存写入岂不是没用了。呵呵~那我要告诉你当然不是,如果你想快速的准确的定位到004AE247这一行的时候,那么他就大有作用了!



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



      B.如何使用内存断点来寻找OEP呢?

      要回答这个问题首先要回答这一个问题:壳是如何解压代码的?



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



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



    而如果你还要继续问我为什么一定要到那个地方才可以下断呢?我难道不可以一开始就下断吗?



    正入我上面所说的,如果你在前面下断很可能壳对code段还没解压完毕呢,这时如果你不停的按F9,你将会看到OD的下方不断的在提示你,“对401000写入中断”“对401002写入中断”“对401004写入中断”.......如果你不介意按F9到他把正个code段写完的话,我除了同情你的“F9”以外,没什么其他的意见!



      那么我们就没有别更快一点的办法了吗?

      有的!那就是我们呼之欲出的两次内存断点办法。

      怎么理解两次内存断点呢?



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



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



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

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



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

    ___________________________________________________________________________________________________________________________________________

    我们走过的一些路,是前辈们走过的老路,我们学习的方法和理论基本上也是前辈们的方法总结,路可以新修、方法可以新想,那要看你花不花心思去学,愿不愿应用你的脑子。
    PYG19周年生日快乐!
  • TA的每日心情
    奋斗
    3 天前
  • 签到天数: 432 天

    [LV.9]以坛为家II

    发表于 2007-4-24 17:29:07 | 显示全部楼层
    讲得这么清楚,如何能不顶??
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表