在无法使用ESP定律时

2019-12-20| 发布者: admin| 查看: |

在存放器里边有许多存放器尽管他们的功用和运用没有任何的差异,可是在长时间的编程和运用中,在程序员习气中现已默许的给每个存放器赋上了特别的意义,比方:eax一般用来做返回值,ecx用于记数等等。在win32的环境下ebp存放器用与存放在进入call今后的a7娱乐登录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值。
2.推行的esp规律
在寻觅oep的时分,往往下断hw esp-4不成功,除了壳代码将硬件断点删除了以外,很可能的状况便是由于壳代码在运转到oep的时分他的esp现已不再是在ep时分的esp了,这样咱们下断当然是不成功的。
那么怎样找到在壳抵达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的值了。
3.实战
来看看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的地点了。
4.总结
上面的这个方法大约能够总结以下的过程:
.直接或直接的断在“最上层的程序”的当地。
.得到“最上层的程序”的ebp的值。
.运用程序初始化的两个固定句子找到壳jmp到oep的仓库值。这个方法有很大的局限性,由于只要vc和delphi程序运用这个初始化的最初。
可是找到“最上层的程序”的方法除了内存断点还有许多方法,例如关于vc来说运用 bp exitprocess也是一个很好的断点,能够直接得到ebp的数值。
5.后话
本来这个方法有很强的前提条件,不是一个很具普遍性的方法,我本来也不想独自的提出来,可是关于jney2兄弟的anti-esp规律来说这个方法却是一个解决之道。
当然还有更多的方法,在这儿我只想说许多工作有矛就有盾,没有什么方法是必定没有缝隙的,仅仅期望这篇文章给咱们阔宽思路,起到抛砖引玉的效果。