[zz]寻找真正的入口(OEP)--广义ESP定律

标 题:【转载】寻找真正的入口(OEP)--广义ESP定律
时 间:2004-09-14,15:43
详细信息:

    寻找真正的入口(OEP)--广义ESP定律

    作者:Lenus
    FROM: poptown.gamewan.com/bbs
    E-MAIL:Lenus_M@163.com

    1.前言
     
      在论坛上看到很多朋友,不知道什么是ESP定律,ESP的适用范围是什么,ESP定律的原理是什么,如何使用ESP定律?看到了我在

    http://poptown.gamewan.com/dispbbs.asp?boardID=5&ID=54&page=1

    调查结果发现,大家对ESP定律很感兴趣,当然因为实在是太好用了,现在我就来告诉大家什么是ESP定律,它的原理是什么!!

    BTW:在看完了手动脱壳入门十八篇了以后,再看这篇文章也许会对你更有帮助!

    在下面地址下载:

    http://soft.winzheng.com/SoftView/SoftView_23125.htm

    2.准备知识

      在我们开始讨论ESP定律之前,我先给你讲解一下一些简单的汇编知识。
      1.call
      这个命令是访问子程序的一个汇编基本指令。也许你说,这个我早就知道了!别急请继续看完。
      call真正的意义是什么呢?我们可以这样来理解:1.向堆栈中压入下一行程序的地址;2.JMP到call的子程序地址处。例如:

    00401029    .  E8 DA240A00    call 004A3508
    0040102E    .  5A             pop edx
    在执行了00401029以后,程序会将0040102E压入堆栈,然后JMP到004A3508地址处!
      
      2.RET
      与call对应的就是RET了。对于RET我们可以这样来理解:1.将当前的ESP中指向的地址出栈;2.JMP到这个地址。
     
      这个就完成了一次调用子程序的过程。在这里关键的地方是:如果我们要返回父程序,则当我们在堆栈中进行堆栈的操作的时候,一定要保证在RET这条指令之前,ESP指向的是我们压入栈中的地址。这也就是著名的“堆栈平衡”原理!

    3.狭义ESP定律
     
      ESP定律的原理就是“堆栈平衡”原理。
     
      让我们来到程序的入口处看看吧!
     
      1.这个是加了UPX壳的入口时各个寄存器的值!
    EAX 00000000
    ECX 0012FFB0
    EDX 7FFE0304
    EBX 7FFDF000
    ESP 0012FFC4
    EBP 0012FFF0
    ESI 77F51778 ntdll.77F51778
    EDI 77F517E6 ntdll.77F517E6
    EIP 0040EC90 note-upx.<ModuleEntryPoint>
    C 0  ES 0023 32bit 0(FFFFFFFF)
    P 1  CS 001B 32bit 0(FFFFFFFF)
    A 0  SS 0023 32bit 0(FFFFFFFF)
    Z 0  DS 0023 32bit 0(FFFFFFFF)
    S 1  FS 0038 32bit 7FFDE000(FFF)
    T 0  GS 0000 NULL
    D 0
    O 0  LastErr ERROR_MOD_NOT_FOUND (0000007E)

      2.这个是UPX壳JMP到OEP后的寄存器的值!
    EAX 00000000
    ECX 0012FFB0
    EDX 7FFE0304
    EBX 7FFDF000
    ESP 0012FFC4
    EBP 0012FFF0
    ESI 77F51778 ntdll.77F51778
    EDI 77F517E6 ntdll.77F517E6
    EIP 004010CC note-upx.004010CC
    C 0  ES 0023 32bit 0(FFFFFFFF)
    P 1  CS 001B 32bit 0(FFFFFFFF)
    A 0  SS 0023 32bit 0(FFFFFFFF)
    Z 1  DS 0023 32bit 0(FFFFFFFF)
    S 0  FS 0038 32bit 7FFDE000(FFF)
    T 0  GS 0000 NULL
    D 0
    O 0  LastErr ERROR_MOD_NOT_FOUND (0000007E)

    呵呵~是不是除了EIP不同以外,其他都一模一样啊!

    为什么会这样呢?
    我们来看看UPX的壳的第一行:

    0040EC90 n>  60               pushad      //****注意这里*****
    0040EC91     BE 15B04000      mov esi,note-upx.0040B015
     
    PUSHAD就是把所有寄存器压栈!我们在到壳的最后看看:

    0040EE0F     61               popad      //****注意这里*****
    0040EE10   - E9 B722FFFF      jmp note-upx.004010CC   //JMP到OEP

    POP就是将所有寄存器出栈!


    而当我们PUSHAD的时候,ESP将寄存器压入了0012FFC0--0012FFA4的堆栈中!如下:

    0012FFA4   77F517E6  返回到 ntdll.77F517E6 来自 ntdll.77F78C4E           //EDI
    0012FFA8   77F51778  返回到 ntdll.77F51778 来自 ntdll.77F517B5          //ESI
    0012FFAC   0012FFF0                                                    //EBP
    0012FFB0   0012FFC4                                                   //ESP
    0012FFB4   7FFDF000                                                  //EBX
    0012FFB8   7FFE0304                                                 //EDX
    0012FFBC   0012FFB0                                                //ECX
    0012FFC0   00000000                                               //EAX

    所以这个时候,在教程上面就告诉我们对ESP的0012FFA4下硬件访问断点。也就是说当程序要访问这些堆栈,从而恢复原来寄存器的值,准备跳向苦苦寻觅的OEP的时候,OD帮助我们中断下来。

    于是我们停在0040EE10这一行!
     
    总结:我们可以把壳假设为一个子程序,当壳把代码解压前和解压后,他必须要做的是遵循堆栈平衡的原理,让ESP执行到OEP的时候,使ESP=0012FFC4。

    4.广义ESP定律

      很多人看完了教程就会问:ESP定律是不是就是0012FFA4,ESP定律的适用范围是不是只能是压缩壳!
     
      我的回答是:NO!

      看完了上面你就知道你如果用0012FFA8也是可以的,ESP定律不仅用于压缩壳他也可以用于加密壳!!!

      首先,告诉你一条经验也是事实---当PE文件运行开始的时候,也就是进入壳的第一行代码的时候。寄存器的值总是上面的那些值,不信你自己去试试!而当到达OEP后,绝大多的程序都第一句都是压栈!(除了BC编写的程序,BC一般是在下面几句压栈)

      现在,根据上面的ESP原理,我们知道多数壳在运行到OEP的时候ESP=0012FFC4。这就是说程序的第一句是对0012FFC0进行写入操作!
     
      最后我们得到了广义的ESP定律,对只要在0012FFC0下,硬件写入断点,我们就能停在OEP的第二句处!!

    下面我们来举个例子,就脱壳进阶第一篇吧!

      载入OD后,来到这里:

    0040D042 N>  B8 00D04000      mov eax,Notepad.0040D000 //停在这里
    0040D047     68 4C584000      push Notepad.0040584C
    0040D04C     64:FF35 00000000 push dword ptr fs:[0]    //第一次硬件中断,F9
    0040D053     64:8925 00000000 mov dword ptr fs:[0],esp
    0040D05A     66:9C            pushfw
    0040D05C     60               pushad
    0040D05D     50               push eax

    直接对0012FFC0下硬件写入断点,F9运行。(注意硬件中断)

    在0040D04C第一次硬件中断,F9继续!

    0040D135     A4               movs byte ptr es:[edi],byte ptr ds:[esi] //访问异常,不管他 shift+F9继续
    0040D136     33C9             xor ecx,ecx
    0040D138     83FB 00          cmp ebx,0
    0040D13B   ^ 7E A4            jle short Notepad.0040D0E1

    第二次硬件中断。

    004058B5       64             db 64                                 //断在这里
    004058B6       89             db 89
    004058B7       1D             db 1D
    004058B8       00             db 00
    004058B9       00             db 00

    这里也不是,F9继续!

    004010CC   /.  55             push ebp
    004010CD   |.  8BEC           mov ebp,esp  //断在这里,哈哈,到了!(如果发现有花指令,用ctrl+A分析一下就能显示出来)
    004010CF   |.  83EC 44        sub esp,44
    004010D2   |.  56             push esi

       快吧!还不过瘾,在来一个例子。

       脱壳进阶第二篇

       如果按上面的方法断不下来,程序直接运行了!没什么,我们在用另一种方法!
     
       载入后停在这里,用插件把OD隐藏!

    0040DBD6 N>^\E9 25E4FFFF      jmp Note_tEl.0040C000                  //停在这里
    0040DBDB     0000             add byte ptr ds:[eax],al
    0040DBDD     0038             add byte ptr ds:[eax],bh
    0040DBDF     A4               movs byte ptr es:[edi],byte ptr ds:[esi]
    0040DBE0     54               push esp

       F9运行,然后用SHIFT+F9跳过异常来到这里:

    0040D817   ^\73 DC            jnb short Note_tEl.0040D7F5       //到这里
    0040D819     CD20 64678F06    vxdcall 68F6764
    0040D81F     0000             add byte ptr ds:[eax],al
    0040D821     58               pop eax

       在这里对0012FFC0下硬件写入断点!(命令行里键入HW 12FFC0)SHIFT+F9跳过异常,就来到OEP的第二行处:(用CTRL+A分析一下)

    004010CC   /.  55             push ebp
    004010CD   |.  8BEC           mov ebp,esp                       //断在这里
    004010CF   |.  83EC 44        sub esp,44
    004010D2   |.  56             push esi
    004010D3   |.  FF15 E4634000  call dword ptr ds:[4063E4]
    004010D9   |.  8BF0           mov esi,eax
    004010DB   |.  8A00           mov al,byte ptr ds:[eax]
    004010DD   |.  3C 22          cmp al,22

       就这样我们轻松搞定了两个加密壳的找OEP问题!

    5.总结

      现在我们可以轻松的回答一些问题了。
     
      1.ESP定律的原理是什么?

      堆栈平衡原理。
     
      2.ESP定律的适用范围是什么?

      几乎全部的压缩壳,部分加密壳。只要是在JMP到OEP后,ESP=0012FFC4的壳,理论上我们都可以使用。但是在何时下断点避开校验,何时下断OD才能断下来,这还需要多多总结和多多积累。欢迎你将你的经验和我们分享。

      3.是不是只能下断12FFA4的访问断点?

      当然不是,那只是ESP定律的一个体现,我们运用的是ESP定律的原理,而不应该是他的具体数值,不能说12FFA4,或者12FFC0就是ESP定律,他们只是ESP定律的一个应用罢了!

      4.对于STOLEN CODE我们怎么办?

      哈哈,这正是寻找STOLEN CODE最好的办法!当我们断下时,正好断在了壳处理STOLEN CODE的地方,在F8一会就到OEP了!

    6.后话
     
     
      以上的方法原理都是我自己总结,自己的经验,如果有什么不对的地方,有什么没解释清楚的地方。还请海涵!但是如果觉得我很厉害,那就大可不必,因为ESP定律也是别人教我的,不是我第一个提出来的!我只是个比你们早飞一点的菜鸟罢了^-^

      看了上面的文字希望能对你在寻找OEP的时候有帮助,但是别忘了一句话:菜鸟认为找OEP很难,高手认为修复才是最难! 好了,下一篇应该写IAT的修复原理了!让我们共同努力吧!

      最后如果转载注明作者并保持文章的完整, 谢谢你看完


posted @ 2008-03-14 20:46  090  阅读(1018)  评论(0编辑  收藏  举报
如有任何的意见和建议,请 E-mail 至 to090@yahoo.com
建议使用 IE 6.0 或 FireFox 2.0 以上版本进行浏览,最佳显示 1024 * 768