EBP详解

article/2025/10/4 8:24:39

 

    在寄存器里面有很多寄存器虽然他们的功能和使用没有任何的区别,但是在长期的编程和使用中,在程序员习惯中已经默认的给每个寄存器赋上了特殊的含义,比 如: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时候的ESP12FFC4)了,这样我们下断当然是不成功的。
那么如何找到在壳到达OEP的时候的堆栈的值将是关键。
在这里我们应用的关键是
Push EBP
MOV Ebp,Esp----
》关键是这句
来解释一下,当程序到达OEP的时候Push EBP这句对于ESP的值来说就是ESP-4,然后是ESP-4赋给了EBP,而做为保存ESP值作用的EBP寄存器在这个最上层的程序中的值将始终 不会改变。虽然他可能在进入子call里面以后会暂时的改变(用于子程序的堆栈平衡)但是在退出了以后依*pop ebp这一句将还原原来的EBP的值。
以这句做为突破口,就是说只要我们能断在最上层的程序中,就能通过观察EBP的值得到壳在JMPOEP的时候的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 ESPEBP这一句,也就是说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).
利用程序初始化的两个固定语句找到壳JMPOEP的堆栈值。这个办法有很大的局限性,因为只有VCdelphi程序使用这个初始化的开头。
但是找到最上层的程序的办法除了内存断点还有很多办法,例如对于VC来说使用 bp ExitProcess也是一个很好的断点,可以直接得到EBP的数值。
5.
后话
原来这个办法有很强的前提条件,不是一个很具普遍性的办法,我原来也不想单独的提出来,但是对于jney2兄弟的anti-ESP定律来说这个办法却是一个解决之道。
当然还有更多的办法,在这里我只想说很多事情有矛就有盾,没有什么办法是一定没有漏洞的,只是希望这篇文章给大家阔宽思路,起到抛砖引玉的作用。

当调用函数时
EBP值已经被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。
此时EBP寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原EBP入栈后的栈顶),
从该地址为基准,向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数局部变量值,
而该地址处又存储着上一层函数调用时的EBP值!

 

10关于变量的赋值,

能否了解到对变量的赋值过程在算法研究中是非常重要的。由于变量是用地址访问的,,因此对形如 MOV [AAA],BBB 的代码要高度关注,它通常是修改变量(地址为AAA,或AAA为寄存器时地址为AAA的值)的值为BBBBBB为寄存器时取BBB的值)。
     
在子程序内部说明的变量称为局部变量,局部变量的作用域是其所在的子程序。从汇编角度来看,局部变量就是一个临时堆栈缓存,用完释放。
00401000 >/$ 6A 04 push 4 ; /Arg2 = 00000004
00401002 |. 6A 03 push 3 ; |Arg1 = 00000003
00401004 |. E8 16000000 call 0040101F ; /Add.0040101F
00401009 |. 8BD8 mov ebx, eax
0040100B |. 6A 00 push 0 ; /ExitCode = 0
0040100D /. FF15 00204000 call [<&KERNEL32.ExitProcess>] ; /ExitProcess

0040101F /$ 55 push ebp ;
保护现场原先的EBP指针
00401020 |. 8BEC mov ebp, esp ;
设置新的EBP指针,指向栈顶
00401022 |. 83EC 04 sub esp, 4 ;
分配局部变量所有空间
00401025 |. 8B45 0C mov eax, [ebp+C] ;
调用参数2
00401028 |. 8B5D 08 mov ebx, [ebp+8] ;
调用参数1
0040102B |. 895D FC mov [ebp-4] , ebx ;
参数1放局部变量里
0040102E |. 0345 FC add eax,[ebp-4] ;
参数2与局部变量相加
00401031 |. 83C4 04 add esp, 4 ;
释放局部变量所有空间
00401034 |. 5D pop ebp ;
恢复现场的ebp指针
00401035 /. C2 0800 retn 8

    在分析汇编代码时总是要遇到无数的Call,对于这些Call,尽量要根据Call之前传递的参数和Call的返回值来判断Call的功能。传递参数的工作必须由函数调用者和函数本身来协调,计算机提供了一种被称为栈的数据结构来支持参数传递。
   
当参数个数多于一个时,按照什么顺序把参数压入堆栈。函数调用后,由谁来把堆栈恢复。在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:
【例】按__stdcall约定调用函数test2(Par1, Par2)
push par2 ;
参数2
push par1 ;
参数1
call test2;
{
push ebp ;
保护现场原先的EBP指针
mov ebp, esp ;
设置新的EBP指针,指向栈顶
mov eax, [ebp+0C] ;
调用参数2
mov ebx, [ebp+08] ;
调用参数1
sub esp, 8 ;
若函数要用局部变量,则要在堆栈中留出点空间

add esp, 8 ;
释放局部变量占用的堆栈
pop ebp ;
恢复现场的ebp指针
ret 8 ;
返回(相当于ret; add esp,8
}
其堆栈调用示意图:
返回值

在调试程序时,不要见Call就跟进,在Call之前所做的所有PUSH动作以及对寄存器的操作都可能是在给函数传递参数,而函数的返回值一般都放在EAX里面,当然这个值可能是一个指针,指向一个数据结构。从汇编角度来看,主要有如下形式:

1)
通过寄存器返回函数值;
2)
通过参数按引用方式返回函数值;
3)
通过全局变量返回函数值;
4)
通过处理器标志返回函数值;
一般情况下,由retrun操作符返回的值放在EAX寄存器之中,如果结果超过这个寄存器的位容量,那么该结果的高32位会加载到EDX寄存器中。 如果返回一个含有几百个字节的结构或者一个近似大小的对象,编译器会在不告诉程序的情况下,给函数传递一个隐式参数,这个指针指向保存的返回结果。


1.2


http://chatgpt.dhexx.cn/article/xyVMC1Ju.shtml

相关文章

esp和ebp详解

一.概念分析 经常看到下面这两句&#xff1a; pushl %ebp movl %esp,%ebp esp是堆栈指针  ebp是基址指针  那两条指令的意思是 将栈顶指向 ebp 的地址  —————————————————————  以下摘自网上一篇文章&#xff1a;  push    ebp  …

栈帧详解ebp、esp

一. 理解栈帧 栈帧是什么&#xff0c;我们基本的理解是栈帧也叫活动记录过程&#xff0c;是编译器用来实现过程 函数调用的一种数据结构。通俗来说栈帧就时C语言函数在调用的过程中的调用原理&#xff0c;就是当我们执行一个函数操作的时候&#xff0c;它的内部是如何实现的呢…

【汇编】esp寻址与ebp寻址

前言&#xff1a;本教程使用的工具是DTDEBUG&#xff0c;讲解的是32位汇编。 1、什么是esp寻址 顾名思义&#xff0c;使用esp这个栈顶指针寄存器去寻找变量对应的地址&#xff0c;就叫做esp寻址。 如下就是一个简单的esp寻址&#xff1a; 像这样&#xff0c;我们通过esp的偏移…

栈帧ebp,esp详解

栈帧%ebp,%esp详解 分类专栏&#xff1a; 汇编 首先应该明白&#xff0c;栈是从高地址向低地址延伸的。每个函数的每次调用&#xff0c;都有它自己独立的一个栈帧&#xff0c;这个栈帧中维持着所需要的各种信息。寄存器ebp指向当前的栈帧的底部&#xff08;高地址&#xff0…

对于ESP、EBP寄存器的理解

转载&#xff1a;https://mp.weixin.qq.com/s/Od9X-qnQ3WWyZiLIS4uPFg 函数调用是编程语言都有的概念&#xff0c;也许你听说过函数调用栈&#xff0c;但是大家都知道函数调用是如何完成的吗&#xff1f;我们为什么要了解这个过程: 对于程序运行机制中的数据结构和实现的了解&…

ebpf简介

目录 什么是eBPFeBPF架构eBPF优势eBPF相关工具 什么是eBPF eBPF 是什么呢&#xff1f; 从它的全称“扩展的伯克利数据包过滤器 (Extended Berkeley Packet Filter)” 来看&#xff0c;它是一种数据包过滤技术&#xff0c;是从 BPF (Berkeley Packet Filter) 技术扩展而来的。顾…

函数栈EIP、EBP、ESP寄存器的作用

这一篇文章咱们就来重新认识一下EIP、EBP、ESP这三个寄存器&#xff0c;寄存器又好几个&#xff0c;但是为什么我们要单独看这几个呢&#xff1f;因为在很多情况下我们在调试的时候最注意的就是这三个寄存器&#xff0c;其实这几个寄存器都是为“栈”而生&#xff0c;下面将结合…

你了解函数调用过程吗?

函数调用是编程语言都有的概念&#xff0c;也许你听说过函数调用栈&#xff0c;但是大家都知道函数调用是如何完成的吗&#xff1f;我们为什么要了解这个过程: 对于程序运行机制中的数据结构和实现的了解&#xff0c;对自己开发程序有着启发作用碰到一些疑难杂症的时候&#x…

ebp/栈帧/call stack

一.什么是ebp&#xff1f; &#xff08;1&#xff09;ESP&#xff1a;栈指针寄存器(extended stack pointer)&#xff0c;其内存放着一个指针&#xff0c;该指针永远指向系统栈最上面一个栈帧的栈顶。 &#xff08;2&#xff09;EBP&#xff1a;基址指针寄存器(extended base …

栈帧详解

一. 理解栈帧 栈帧是什么&#xff0c;我们基本的理解是栈帧是栈帧也叫过程 活动记录&#xff0c;是 编译器用来实现过程/ 函数调用的一种数据结构。通俗来说栈帧就时C语言函数在调用的过程中的调用原理&#xff0c;就是当我们执行一个函数操作的时候&#xff0c;它的内部是如何…

EBP 和 ESP 详解

基本概念&#xff1a; &#xff08;1&#xff09;ESP&#xff1a;栈指针寄存器(extended stack pointer)&#xff0c;其内存放着一个指针&#xff0c;该指针永远指向系统栈最上面一个栈帧的栈顶。 &#xff08;2&#xff09;EBP&#xff1a;基址指针寄存器(extended base poin…

基于生命周期的开发方法——迭代开发方法

迭代开发方法 上一篇原型方法只是一种需求验证的手段&#xff0c;如果将其思想运用到整个开发过程&#xff0c;使得每个阶段的任务经过反复多次&#xff0c;或者将分析、设计、实施的周期反复多次&#xff0c;通过一次次迭代&#xff0c;不断在原来的基础上完善和修正&#xf…

2.迭代开发的过程是怎么样的

敏捷开发系列文章目录 在讨论PO如何给团队讲好故事这个问题之前&#xff0c;先给大家了解一些基本的敏捷概念&#xff0c;然后讲讲我们敏捷团队构成与整个敏捷开发的过程。 当初敏捷老师讲课的时候就跟我们所过&#xff0c;敏捷没有什么具体的形式&#xff0c;每个敏捷团队可能…

RUP之动态结构:迭代开发

迭代过程一般分为四个阶段&#xff1a;初始、细化、构造和移交&#xff0c;简称为I,E,C和T。每个阶段以一个重要的里程碑(milestone)结束。 初始(Inception)阶段 确定最终产品的构想及其业务用例、并定义项目范围 初始阶段以生命周期目标(LCO)里程碑为结束点 细化(Elaborat…

开发模式(敏捷开发,瀑布式开发,螺旋型开发,迭代开发,devOps开发)

一. 敏捷开发 以人为核心、迭代、循序渐进的开发方式 简化文档&#xff0c;提取文档重点&#xff0c;主要在于人与人之间的沟通&#xff0c; 对开发产品进行迭代&#xff0c;最终完成开发。 迭代&#xff1a;迭代是指把一个复杂且开发周期很长的开发任务&#xff0c;分解为很…

敏捷开发-快速迭代

&#xff08;转自:http://blog.csdn.net/xiaoxian8023/article/details/8883791&#xff09; 今天跟大家分享的是“敏捷开发、快速迭代”。我们大都采用的是“瀑布开发模式”&#xff0c;有了问题&#xff0c;就得返工&#xff0c;虽然最终的产品会比较齐全完善&#xff0c;但是…

一文搞定软件过程模型——瀑布模型、增量式开发/增量开发与迭代开发的区别

软件开发比较经典的过程模型有&#xff1a; 瀑布模型&#xff1a;该模型将基本的过程活动、描述、开发、有效性验证和进化&#xff0c;看成是一些界限分明的独立的过程阶段&#xff0c;例如&#xff0c;需求描述阶段、软件设计阶段、实现阶段、测试阶段等。增量式开发&#xf…

软件迭代开发流程

如果对python自动化测试、web自动化、接口自动化、移动端自动化、大型互联网架构技术、面试经验交流等等感兴趣的老铁们&#xff0c;可以关注我。我会在公众号&#xff08;程序员阿沐&#xff09;/群里&#xff08;810119819&#xff09;不定期的发放免费的资料链接&#xff0c…

迭代开发流程

转载于:https://www.cnblogs.com/gispathfinder/p/8747869.html

git 迭代开发分支流程规范

前言 Git 的名称太响了&#xff0c;相信大家都听说过&#xff0c;鼎鼎大名的同性交友网站 GitHub 就是基于 Git 作为唯一的版本库格式进行托管的平台。本篇不详细介绍 Git 的使用&#xff0c;仅介绍基于 Git 的开发分支流程规范&#xff0c;需要对 Git有一定的了解。 简述 G…