首页
社区
课程
招聘
[推荐]推广的ESP定律---EBP的妙用
发表于: 2009-8-13 17:12 10071

[推荐]推广的ESP定律---EBP的妙用

2009-8-13 17:12
10071
推广的ESP定律---EBP的妙用
1.前言
  
   几天前,jney2兄弟发表了《如何阻击“ESP定律”》一文,对于anti-ESP定律提出了非常建设性的方案,通过这篇文章我们知道ESP定律的原理和他的局限性,但是对于不能使用ESP定律的壳可不占少数哦。在这里我想简单的提出一个当我们面对无法使用ESP定律时的办法。
--------------------------------------------------
2.正文
  
   i.了解EBP寄存器
   在寄存器里面有很多寄存器虽然他们的功能和使用没有任何的区别,但是在长期的编程和使用中,在程序员习惯中已经默认的给每个寄存器赋上了特殊的含义,比如:EAX一般用来做返回值,ECX用于记数等等
   在win32的环境下EBP寄存器用与存放在进入call以后的ESP的值,便于退出的时候回复ESP的值,达到堆栈平衡的目的。

   应用以前说过的一段话:

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

   为什么要这样呢?为什么几乎每个程序都是的开头能?
因为如果我们写过C等函数的时候就应该清楚,程序的开始是以一个主函数main()为开始的,而函数在访问的过程中最重要的事情就是要确保堆栈的平衡,而在win32的环境下保持平衡的办法是这样的:
1.让EBP保存ESP的值;
2.在结束的时候调用
mov esp,ebp
pop ebp
retn
或者是
leave
retn
两个形式是一个意思。

这样做的好处是不用考虑ESP等于多少,PUSH了多少次,要POP多少次了,因为我们知道EBP里面放的是开始时候的ESP值。

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

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

在这里我们应用的关键是

Push EBP
MOV Ebp,Esp----》关键是这句

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

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

iii.实战

点击浏览该文件

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

载入程序后来到最后的一个异常

0040ED85     2BDB          sub ebx,ebx                         //停在这里
0040ED87     64:8F03       pop dword ptr fs:[ebx]
0040ED8A     58             pop eax
0040ED8B     5D             pop ebp
0040ED8C     2BFF          sub edi,edi
0040ED8E     EB 01          jmp short pespin1_.0040ED91
0040ED90     C466 81       les esp,fword ptr ds:[esi-7F]

我用使用内存断点办法来到FOEP处

004010D3     0000          add byte ptr ds:[eax],al
004010D5     0000          add byte ptr ds:[eax],al
004010D7     0000          add byte ptr ds:[eax],al
004010D9     0000          add byte ptr ds:[eax],al
004010DB     0000          add byte ptr ds:[eax],al
004010DD     0000          add byte ptr ds:[eax],al
004010DF     75 1B          jnz short pespin1_.004010FC             //这里是FOEP
004010E1     56             push esi
004010E2     FF15 99F44000 call dword ptr ds:[40F499]
004010E8     8BF0          mov esi,eax
004010EA     8A00          mov al,byte ptr ds:[eax]

好了,这里就是“最上层的程序”的地方了,看看寄存器

EAX 00141E22
ECX 0040C708 pespin1_.0040C708
EDX 0040C708 pespin1_.0040C708
EBX 0040C708 pespin1_.0040C708                  
ESP 0012F978
EBP 0012F9C0                               //注意这里
ESI 00141EE0
EDI 0040E5CD pespin1_.0040E5CD
EIP 004010DF pespin1_.004010DF

看到了吧,EBP=0012F9C0,我们来想象一下这个值是怎么得到的。

首先肯定是通过MOV ESP,EBP这一句,也就是说ESP这时是0012F9C0的,

然而上面还有一句PUSH EBP也就是说ESP在到达OEP的时候应该是0012F9C4的。

好了得到这个结论我们就能很快的找到stolen code的所在了。

重来停在最后的异常

0040ED85     2BDB          sub ebx,ebx                         //停在这里
0040ED87     64:8F03       pop dword ptr fs:[ebx]
0040ED8A     58             pop eax
0040ED8B     5D             pop ebp
0040ED8C     2BFF          sub edi,edi
0040ED8E     EB 01          jmp short pespin1_.0040ED91
0040ED90     C466 81       les esp,fword ptr ds:[esi-7F]

然后下断HW 0012F9C0 ,F9运行

来到这里

0040D8FB     61             popad
0040D8FC     55             push ebp
0040D8FD     EB 01          jmp short pespin1_.0040D900           //停在这里
0040D8FF     318B ECEB01AC xor dword ptr ds:[ebx+AC01EBEC],ecx
0040D905     83EC 44       sub esp,44
0040D908     EB 01          jmp short pespin1_.0040D90B
0040D90A     72 56          jb short pespin1_.0040D962
0040D90C     EB 01          jmp short pespin1_.0040D90F
0040D90E     95             xchg eax,ebp
0040D90F     FF15 6CF34000 call dword ptr ds:[40F36C]
0040D915     EB 01          jmp short pespin1_.0040D918

于是就很快的找到了stolen code的所在了
--------------------------------------------------
3.总结
   上面的这个办法大概可以总结以下的步骤:
1.直接或间接的断在“最上层的程序”的地方。
2.得到“最上层的程序”的EBP的值。
2.利用程序初始化的两个固定语句找到壳JMP到OEP的堆栈值。

这个办法有很大的局限性,因为只有VC和delphi程序使用这个初始化的开头。

但是找到“最上层的程序”的办法除了内存断点还有很多办法,例如对于VC来说使用 bp ExitProcess也是一个很好的断点,可以直接得到EBP的数值。
--------------------------------------------------
4.后话
   原来这个办法有很强的前提条件,不是一个很具普遍性的办法,我原来也不想单独的提出来,但是对于jney2兄弟的anti-ESP定律来说这个办法却是一个解决之道。
   当然还有更多的办法,在这里我只想说很多事情有矛就有盾,没有什么办法是一定没有漏洞的,只是希望这篇文章给大家阔宽思路,起到抛砖引玉的作用

[课程]Linux pwn 探索篇!

收藏
免费 0
支持
分享
最新回复 (17)
雪    币: 9583
活跃值: (1935)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
楼主的这篇文章条理很清楚!适合学习
2009-8-14 20:32
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
好文章,学习了,谢谢楼主。。
2009-8-17 17:00
0
雪    币: 235
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
菜鸟来学习了
2009-8-17 20:39
0
雪    币: 81
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
我是只新鸟,还是看不懂
2009-8-17 22:37
0
雪    币: 208
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
条条大道通罗马,这个也是一个很好的方法啊
2009-8-18 12:53
0
雪    币: 209
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
学习学习,谢谢楼主!
2009-8-18 14:34
0
雪    币: 398
活跃值: (49)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
我也来学习一下,不过目前还只是有一点点头绪
2009-8-19 23:22
0
雪    币: 248
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
不错,学习了!
2009-8-30 12:46
0
雪    币: 433
活跃值: (1875)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
10
飘过!              !
2009-8-30 13:01
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
11
我看过之后,就加精了
2009-8-30 21:18
0
雪    币: 292
活跃值: (110)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
12
很久没有上来学习了,大家都还很努力呀。
2009-9-1 23:27
0
雪    币: 306
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
早就看过这篇文章了
2009-9-12 18:59
0
雪    币: 112
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
拜读后,获益良多
2009-9-12 21:19
0
雪    币: 211
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
膜拜 学习 了 感谢LZ 不错的文章
2009-9-12 21:49
0
雪    币: 421
活跃值: (83)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
一直对于ESP定律的原理不是很熟悉。多谢LZ的精彩文章
2009-9-13 17:20
0
雪    币: 199
活跃值: (65)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
17
很好的文章!
2010-7-28 20:42
0
雪    币: 531
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
来学习!谢谢!
2010-8-5 17:11
0
游客
登录 | 注册 方可回帖
返回
//