宝峰科技

 找回密码
 注册

QQ登录

只需一步,快速开始

智能终端设备维修查询系统注册会员邮箱认证须知!
查看: 3485|回复: 0

当无法使用ESP定律脱壳时——EBP的妙用

[复制链接]
  • TA的每日心情
    开心
    2024-12-9 18:45
  • 签到天数: 124 天

    [LV.7]常住居民III

    admin 发表于 2010-12-3 13:05:17 | 显示全部楼层 |阅读模式

    欢迎您注册加入!这里有您将更精采!

    您需要 登录 才可以下载或查看,没有账号?注册

    x
          在寄存器里面有很多寄存器虽然他们的功能和使用没有任何的区别,但是在长期的编程和使用中,在程序员习惯中已经默认的给每个寄存器赋上了特殊的含义,比如:EAX一般用来做返回值,ECX用于记数等等。在win32的环境下EBP寄存器用与存放在进入call以后的ESP的值,便于退出的时候回复ESP的值,达到堆栈平衡的目的。

          应用以前说过的一段话:

          原程序的OEP,通常是一开始以 Push EBP 和MOV Ebp,Esp这两句开始的,不用我多说大家也知道这两句的意思是以EBP代替ESP,作为访问堆栈的指针。

          为什么要这样呢?为什么几乎每个程序都是的开头能?因为如果我们写过C等函数的时候就应该清楚,程序的开始是以一个主函数main()为开始的,而函数在访问的过程中最重要的事情就是要确保堆栈的平衡,而在win32的环境下保持平衡的办法是这样的:

          1.让EBP保存ESP的值;

          2.在结束的时候调用
    1. mov esp,ebp
    2. pop ebp
    3. retn
    复制代码
    或者是
    1. leave
    2. retn
    复制代码
    两个形式是一个意思。
    这样做的好处是不用考虑ESP等于多少,PUSH了多少次,要POP多少次了,因为我们知道EBP里面放的是开始时候的ESP值。

          2.推广的ESP定律

          在寻找OEP的时候,往往下断HW ESP-4不成功,除了壳代码将硬件断点删除了以外,很可能的情况就是因为壳代码在运行到OEP的时候他的ESP已经不再是在EP时候的ESP(12FFC4)了,这样我们下断当然是不成功的。

          那么如何找到在壳到达OEP的时候的堆栈的值将是关键。

          在这里我们应用的关键是
    1. Push EBP
    2. MOV Ebp,Esp----》关键是这句
    复制代码
    解释一下,当程序到达OEP的时候Push EBP这句对于ESP的值来说就是ESP-4,然后是ESP-4赋给了EBP,而做为保存ESP值作用的EBP寄存器在这个“最上层的程序”中的值将始终不会改变。虽然他可能在进入子call里面以后会暂时的改变(用于子程序的堆栈平衡)但是在退出了以后依*pop ebp这一句将还原原来的EBP的值。

          以这句做为突破口,就是说只要我们能断在“最上层的程序”中,就能通过观察EBP的值得到壳在JMP到OEP的时候的ESP的值了。

          3.实战

          来看看pespin1.1的壳,在pespin1.0的壳中,我们使用HW 12FFC0能很容易的找到stolen code的地方,但是到pespin1.1的时候,我们就不行了。用HW 12FFC0根本断不下来。

          现在我们就使用这个推广的ESP定律,载入程序后来到最后的一个异常
    1. 0040ED85 2BDB sub ebx,ebx //停在这里
    2. 0040ED87 64:8F03pop dword ptr fs:[ebx]
    3. 0040ED8A 58 pop eax
    4. 0040ED8B 5D pop ebp
    5. 0040ED8C 2BFF sub edi,edi
    6. 0040ED8E EB 01jmp short pespin1_.0040ED91
    7. 0040ED90 C466 81les esp,fword ptr ds:[esi-7F]
    复制代码
    我用使用内存断点办法来到FOEP处
    1. 004010D3 0000 add byte ptr ds:[eax],al
    2. 004010D5 0000 add byte ptr ds:[eax],al
    3. 004010D7 0000 add byte ptr ds:[eax],al
    4. 004010D9 0000 add byte ptr ds:[eax],al
    5. 004010DB 0000 add byte ptr ds:[eax],al
    6. 004010DD 0000 add byte ptr ds:[eax],al
    7. 004010DF 75 1Bjnz short pespin1_.004010FC //这里是FOEP
    8. 004010E1 56 push esi
    9. 004010E2 FF15 99F44000call dword ptr ds:[40F499]
    10. 004010E8 8BF0 mov esi,eax
    11. 004010EA 8A00 mov al,byte ptr ds:[eax]
    复制代码
    好了,这里就是“最上层的程序”的地方了,看看寄存器
    1. EAX 00141E22
    2. ECX 0040C708 pespin1_.0040C708
    3. EDX 0040C708 pespin1_.0040C708
    4. EBX 0040C708 pespin1_.0040C708
    5. ESP 0012F978
    6. EBP 0012F9C0//注意这里
    7. ESI 00141EE0
    8. EDI 0040E5CD pespin1_.0040E5CD
    9. EIP 004010DF pespin1_.004010DF
    复制代码
    看到了吧,EBP=0012F9C0,我们来想象一下这个值是怎么得到的。

          首先肯定是通过MOV ESP,EBP这一句,也就是说ESP这时是0012F9C0的,然而上面还有一句PUSH EBP也就是说ESP在到达OEP的时候应该是0012F9C4的。好了得到这个结论我们就能很快的找到stolen code的所在了。

          重来停在最后的异常
    1. 0040ED85 2BDB sub ebx,ebx //停在这里
    2. 0040ED87 64:8F03pop dword ptr fs:[ebx]
    3. 0040ED8A 58 pop eax
    4. 0040ED8B 5D pop ebp
    5. 0040ED8C 2BFF sub edi,edi
    6. 0040ED8E EB 01jmp short pespin1_.0040ED91
    7. 0040ED90 C466 81les esp,fword ptr ds:[esi-7F]
    复制代码
    然后下断HW 0012F9C0 ,F9运行,来到这里
    1. 0040D8FB 61 popad
    2. 0040D8FC 55 push ebp
    3. 0040D8FD EB 01jmp short pespin1_.0040D900 //停在这里
    4. 0040D8FF 318B ECEB01ACxor dword ptr ds:[ebx+AC01EBEC],ecx
    5. 0040D905 83EC 44sub esp,44
    6. 0040D908 EB 01jmp short pespin1_.0040D90B
    7. 0040D90A 72 56jb short pespin1_.0040D962
    8. 0040D90C EB 01jmp short pespin1_.0040D90F
    9. 0040D90E 95 xchg eax,ebp
    10. 0040D90F FF15 6CF34000call dword ptr ds:[40F36C]
    11. 0040D915 EB 01jmp short pespin1_.0040D918
    复制代码
    于是就很快的找到了stolen code的所在了。

          4.总结

          上面的这个办法大概可以总结以下的步骤:

          (1).直接或间接的断在“最上层的程序”的地方。

          (2).得到“最上层的程序”的EBP的值。

          (3).利用程序初始化的两个固定语句找到壳JMP到OEP的堆栈值。这个办法有很大的局限性,因为只有VC和delphi程序使用这个初始化的开头。

          但是找到“最上层的程序”的办法除了内存断点还有很多办法,例如对于VC来说使用 bp ExitProcess也是一个很好的断点,可以直接得到EBP的数值。

          5.后话

          原来这个办法有很强的前提条件,不是一个很具普遍性的办法,我原来也不想单独的提出来,但是对于jney2兄弟的anti-ESP定律来说这个办法却是一个解决之道。

          当然还有更多的办法,在这里我只想说很多事情有矛就有盾,没有什么办法是一定没有漏洞的,只是希望这篇文章给大家阔宽思路,起到抛砖引玉的作用。
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    免责声明

    本站中所有被研究的素材与信息全部来源于互联网,版权争议与本站无关。本站所发布的任何软件编程开发或软件的逆向分析文章、逆向分析视频、补丁、注册机和注册信息,仅限用于学习和研究软件安全的目的。全体用户必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。学习编程开发技术或逆向分析技术是为了更好的完善软件可能存在的不安全因素,提升软件安全意识。所以您如果喜欢某程序,请购买注册正版软件,获得正版优质服务!不得将上述内容私自传播、销售或者用于商业用途!否则,一切后果请用户自负!

    QQ|Archiver|手机版|小黑屋|联系我们|宝峰科技 ( 滇公网安备 53050202000040号 | 滇ICP备09007156号-2 )

    Copyright © 2001-2023 Discuz! Team. GMT+8, 2024-12-22 16:06 , File On Powered by Discuz! X3.49

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