缓冲区溢出学习

本文深入探讨了缓冲区溢出的概念,涉及寄存器ESP、EBP、EIP的作用,函数调用模式,以及如何通过GDB和Python脚本调试。通过示例分析了堆栈溢出、堆溢出、格式化字符串错误等场景,并提出了预防缓冲区溢出的方法,如使用安全函数和二进制分析工具。
摘要由CSDN通过智能技术生成

一、寄存器ESP、EBP、EIP

  1. CPU的ESP寄存器存放当前线程的栈顶指针,
  2. EBP寄存器中保存当前线程的栈底指针。
  3. CPU的EIP寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行

二、函数调用模式

堆栈由逻辑堆栈帧组成。当调用函数时逻辑堆栈帧被压入栈中,当函数返回时逻辑堆栈帧被从栈中弹出。堆栈帧包括函数的参数,函数地局部变量,以及恢复前一个堆栈帧所需要的数据,其中包括在函数调用时指令指针(IP)的值。

当一个例程被调用时所必须做的第一件事是保存前一个 FP(这样当例程退出时就可以恢复)。然后它把SP复制到FP,创建新的FP,把SP向前移动为局部变量保留空间。这称为例程的序幕(prolog)工作。当例程退出时,堆栈必须被清除干净,这称为例程的收尾(epilog)工作。Intel的ENTER和LEAVE指令,Motorola的LINK和 UNLINK指令,都可以用于有效地序幕和收尾工作

三、函数示例原理

void function(int a, int b, int c) 
{
    char buffer1[5];
    char buffer2[10];
}
void main() 
{
    function(1,2,3);
}

使用gcc的-S选项编译, 可以产生汇编代码输出
$ gcc -S -o example1.s example1.c
对function()的调用被汇编成如下代码:

pushl \$3
pushl \$2
pushl \$1
call function

以从后往前的顺序将function的三个参数压入栈中, 然后调用function()

pushl %ebp
movl %esp,%ebp
subl $20,%esp

将帧指针EBP压入栈中. 然后把当前的SP复制到EBP, 使其成为新的帧指针. 我们把这个被保存的FP叫做SFP. 接下来将SP的值减小, 为局部变量保留空间.

我们必须牢记:内存只能以字为单位寻址. 在这里一个字是4个字节, 32位. 因此5字节的缓冲区会占用8个字节(2个字)的内存空间, 而10个字节的缓冲区会占用12个字节(3个字)的内存空间. 这就是为什么SP要减掉20的原因。

地址演示
从上图来看,假如我们输入的buffer1超长了,直接覆盖掉后面的sfp和ret,就可以修改该函数的返回地址了。

四、具体实例

函数foo是正常的函数,在main函数中被调用,执行了一段非常不安全的strcpy工作。利用不安全的strcpy,我们可 以传入一个超过缓冲区buf长度的字符串,执行拷贝后,缓冲区溢出,把ret返回地址修改成函数bar的地址,达到调用函数bar的目的。

#include <stdio.h>
#include <string.h>
void foo(const ch
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值