在寄存器里面有很多寄存器虽然他们的功能和使用没有任何的区别,但是在长期的编程和使用中,在程序员习惯中已经默认的给每个寄存器赋上了特殊的含义,比如: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值。 



2.推广的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的值了。 



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.总结 



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



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



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



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



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



5.后话 



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



当然还有更多的办法,在这里我只想说很多事情有矛就有盾,没有什么办法是一定没有漏洞的,只是希望这篇文章给大家阔宽思路,起到抛砖引玉的作用。

当调用函数时

原EBP值已经被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。

此时EBP寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原EBP入栈后的栈顶),

从该地址为基准,向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数局部变量值,

而该地址处又存储着上一层函数调用时的EBP值!

总结一个for循环的反汇编结构如下:



mov <循环变量>,<初值>

jmp 检查循环条件B

A: (修改循环变量)

...

...



B: cmp <循环变量>,<限制条件>

jge 跳出循环

(循环体)

...

...

jmp 修改循环变量A



;if的模板如下



;cmp <各种条件>

;各种跳转跳到下一个分支



;else if模板



;jmp 跳出判断

;cmp <条件>

;各种跳转跳到下一个分支





;switch()的模板如下:



;cmp <条件1>

;je <case 分支1>

;cmp <条件2>

;je <case 分支2>

;...

;...

;jmp <default分支>

了解EBP指针的更多相关文章

  1. esp和ebp指针

    gdb调试的时候会出现esp和ebp这两个指针,而这两个指针为我们查看栈的情况提供了方便. 简单点说,esp指向栈顶,而ebp指向栈底.例如一段程序: #include <stdio.h> ...

  2. [Android Pro] ESP和EBP 栈顶指针和栈底指针

    cp:  http://blog.csdn.net/hutao1101175783/article/details/40128587 (1)ESP:栈指针寄存器(extended stack poin ...

  3. 从汇编看c++中成员函数指针(一)

    下面先来看c++的源码: #include <cstdio> using namespace std; class X { public: int get1() { ; } virtual ...

  4. ASM X86&&X64 Registers 对寄存器ESP和EBP的一些理解

    ESP EIP EBP : frame pointer(base address of stack) Calling Convention: 调用约定 为什么fun调用之后 esp -ebp = 20 ...

  5. 对寄存器ESP和EBP的一些理解

    PS:EBP是当前函数的存取指针.即存储或者读取数时的指针基地址:ESP就是当前函数的栈顶指针. 每一次发生函数的调用(主函数调用子函数)时,在被调用函数初始时,都会把当前函数(主函数)的EBP压栈, ...

  6. 汇编 EBP ,ESP 寄存器

    知识点:  CALL框架  EBP寄存器 栈底指针  ESP寄存器 栈顶指针 一.EBP栈底指针 EBP是一个特殊的寄存器,通过EBP+偏移量 可以访问CALL里边的局部变量.它的低16位叫BP ...

  7. 【转】 关于寄存器ESP和EBP的一些理解

    原文: http://blog.csdn.net/zsJum/article/details/6117043 一直对寄存器ESP和EBP的概念总是有些混淆,查看定义ESP是栈顶指针,EBP是存取堆栈指 ...

  8. (转)对于ESP、EBP寄存器的理解

    原文地址https://blog.csdn.net/yeruby/article/details/39780943 esp是栈指针,是cpu机制决定的,push.pop指令会自动调整esp的值: eb ...

  9. 使用gdb查看栈帧的情况,有ebp

    0x7fffffffdb30:    0x00000000    0x00000000    0xf7ffe700    0x0000001a0x7fffffffdb40:    0xffffdc98 ...

随机推荐

  1. Hive/Impala批量插入数据

    问题描述 现有几千条数据,需要插入到对应的Hive/Impala表中.安排给了一个同事做,但是等了好久,反馈还没有插入完成--看到他的做法是:对每条数据进行处理转换为对应的insert语句,但是,实际 ...

  2. 《带你装B,带你飞》pytest成神之路2- 执行用例规则和pycharm运行的三种姿态

    1. 简介 今天北京下的雪好大好美啊!!!哎呀,忘记拍照片了,自己想象一下吧.言归真传,今天还是开始pytest的学习和修炼,上一篇写完后群里反响各式各样的,几家欢乐几家愁,有的高兴说自己刚好要用到了 ...

  3. CSS单行文字超出省略

    .ellipsis { white-space:nowrap overflow:hidden text-overflow:ellipsis }

  4. 为云而生,腾讯云服务器操作系统TencentOS内核正式开源

    ​1月9日,腾讯云宣布将开源其服务器操作系统TencentOS内核.相比业内其它版本Linux 内核,腾讯云 TencentOS 内核在资源调度弹性.容器支持.系统性能及安全等层面极具竞争力,特别适合 ...

  5. C++ | C++ 基础知识 | 类型与声明

    一.类型 C++ 包含一整套基本类型,这些类型对应计算机最基本的存储单元并且展现 1.0 布尔值 一个布尔变量(bool)的取值或者是 true 或者是 false,布尔变量常用于表达逻辑运算结果. ...

  6. Download EditPlus Text Editor

    突然发现EditPlus还是很强大的,很好用,破解也很方便,有个牛人做了在线生成验证码,只能说服!! 下边把官网的最新下载地址贴出,当然还有在线生成验证码喽. EditPlus Text Editor ...

  7. Helm, 在Kubernetes中部署应用的利器

    一.背景 Kubernetes(k8s)是一个基于容器技术的分布式架构领先方案.它在Docker技术的基础上,为容器化的应用提供部署运行.资源调度.服务发现和动态伸缩等一系列完整功能,提高了大规模容器 ...

  8. wireshark使用过程中,卡死未响应

    原因 : 未知 处理办法:1.重装wireshark ----------无效果 2.卸载有道词典-----------成功,wireshark正常运行,重装有道词典该问题必现,所以问题由有道词典引起 ...

  9. Ubuntu TTY 字体大小 目录颜色 中文乱码 设置

    TTY有很多不舒服的地方,没有中文 目录是深蓝色的看不清楚 字太小. 通过设置让终端更舒服一些. 进入TTY 从桌面进入TTY: 按`Ctrl+Alt+F[1-9] 有的版本图形界面在F7和F8,有的 ...

  10. USACO简介导论

      1000: USACO简介 时间限制: 1 Sec  内存限制: 128 MB提交: 8  解决: 7[提交] [状态] [讨论版] [命题人:外部导入] 题目描述 来源/分类 USACO-00  ...