缓冲区溢出:什么是缓冲区溢出?

缓冲区,简单说来是块连续计算机内存区域, 可以保存相同数据类型多个例子动态变量在运行时定位于堆栈的中 我们这里只关心动态缓冲区溢出问题, 即基于堆栈缓冲区溢出
进程内存组织形式
个进程在内存中被分成 3个区域: 文本, 数据和堆栈
文本区域是由确定, 包括代码(指令)和只读数据 该区域相当于可执行文件文本段 这个区域通常被标记为只读, 任何对其写入操作都会导致段(segmentation violation)
数据区域包含了已化和未数据 静态变量储存在这个区域中

/------------------\ 内存低地址
| |
| 文本 |
| |
|------------------|
| (已化) |
| 数据 |
| (未化) |
|------------------|
| |
| 堆栈 |
| |
\------------------/ 内存高地址

堆栈是个后进先处(LIFO)队列

为什么要使用堆栈?
个过程可以象跳转(jump)命令那样改变控制流程, 但是和跳转区别是, 当工作完成时,把控制权返回给的后语句或指令 这种高级抽象实现起来要靠堆栈帮助
堆栈也用于给中使用局部变量动态分配空间, 同样给传递参数和返回值也要用到堆栈

堆栈区详解
堆栈是块保存数据连续内存 个名为堆栈指针(SP)寄存器指向堆栈顶部堆栈底部在个固定地址 堆栈大小在运行时由内核动态地调整

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

堆栈既可以向下增长(向内存低地址)也可以向上增长, 这依赖于具体实现在我们例子中, 堆栈是向下增长堆栈指针(SP)也是依赖于具体实现它可以指向堆栈最后地址,或者指向堆栈的后个空闲可用地址 在我们讨论当中, SP指向堆栈最后地址

除了堆栈指针(SP指向堆栈顶部低地址)的外, 为了使用方便还有指向帧内固定地址指针叫做帧指针(FP)有些文章把它叫做局部基指针(LB-local base poer)从理论上来说, 局部变量可以用SP加偏移量来引用 然而, 当有字被压栈和出栈后, 这些偏移量就变了 尽管在某些情况下编译器能够跟踪栈中字操作, 由此可以修正偏移量, 但是在某些情况下不能而且在所有情况下, 要引入可观管理开销 而且在有些机器上, 比如Intel处理器, 由SP加偏移量访问个变量需要多条指令才能实现

因此, 许多编译器使用第 2个寄存器, FP, 对于局部变量和参数都可以引用, 它们到FP距离不会受到PUSH和POP操作影响 在Intel CPU中, BP(EBP)用于这个目 在Motorola CPU中, 除了A7(堆栈指针SP)的外任何地址寄存器都可以做FP考虑到我们堆栈增长方向, 从FP位置开始计算, 参数偏移量是正值, 而局部变量偏移量是负值

个例程被时所必须做件事是保存前个FP(这样当例程退出时就可以恢复) 然后它把SP复制到FP, 创建新FP, 把SP向前移动为局部变量保留空间 这称为例程序幕(prolog)工作当例程退出时, 堆栈必须被清除干净, 这称为例程收尾(epilog)工作 IntelENTER和LEAVE指令, MotorolaLINK和UNLINK指令, 都可以用于有效地序幕和收尾工作
这里利用了个简单例子来做堆栈溢出举例首先描述了该例子编
译后内存分配情况然后修改这个例子使它成为个典型溢出程
分析溢出时堆栈情况

------------------------------------------------------------------

个简单堆栈例子
example1.c:
------------------------------------------------------------------
void function( a, b, c) {
char buffer1[5];
char buffer2[10];
}

void {
function(1,2,3);
}
------------------------------------------------------------------
使用gcc-S选项编译, 以产生汇编代码输出:
$ gcc -S -o example1.s example1.c

通过查看汇编语言输出, 我们看到对function被翻译成:
pushl $3
pushl $2
pushl $1
call function

以从后往前顺序将function 3个参数压入栈中, 然后function 指令call会把指令指针(IP)也压入栈中 我们把这被保存IP称为返回地址(RET)中所做件事情是例程序幕工作:
pushl ëp
movl %esp,ëp
subl $20,%esp

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

内存只能以字为单位寻址 个字是4个字节, 32位 因此5字节缓冲区会占用8个字节(2个字)内存空间, 而10个字节缓冲区会占用12个字节(3个字)内存空间 这就是为什么SP要减掉20原因 这样我们就可以想象function时堆栈模样(每个空格代表个字节):
内存低地址 内存高地址
buffer2 buffer1 sfp ret a b c
<------ [ ][ ][ ][ ][ ][ ][ ]
堆栈顶部 堆栈底部

制造缓冲区溢出
现在试着修改我们第个例子, 让它可以覆盖返回地址, 而且使它可以执行任意代码堆栈中在buffer1的前是SFP, SFP的前是返回地址 ret从buffer1结尾算起是4个字节应该记住是buffer1实际上是2个字即8个字节长 因此返回地址从buffer1开头算起是12个字节 我们会使用这种思路方法修改返回地址, 跳过后面赋值语句'x=1;', 为了做到这点我们把返回地址加上8个字节 代码看起来是这样:
example3c:
--------------------------------------------------------------------
void function( a, b, c) {
char buffer1[5];
char buffer2[10];
*ret;

ret = buffer1 + 12;
(*ret) 8;
}

void {
x;

x = 0;
function(1,2,3);
x = 1;
prf("%d\n",x);
}
-------------------------------------------------------------------
我们把buffer1地址加上12, 所得新地址是返回地址储存地方 我们想跳过赋值语句而直接执行prf

如何知道应该给返回地址加8个字节呢? 我们先前使用过个试验值(比如1), 编译该, 祭出工具gdb:

-----------------------------------------------------------------
[aleph1]$ gdb example3
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions
There is absolutely no warranty for GDB; type "show warranty" for details
GDB 415 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc...
(no debugging symbols found)...
(gdb) disassemble
Dump of assembler code for function :
0x8000490 : pushl ëp
0x8000491 : movl %esp,ëp
0x8000493 : subl $0x4,%esp
0x8000496 : movl $0x0,0xfffffffc(ëp)
0x800049d : pushl $0x3
0x800049f : pushl $0x2
0x80004a1 : pushl $0x1
0x80004a3 : call 0x8000470
0x80004a8 : addl $0xc,%esp
0x80004ab : movl $0x1,0xfffffffc(ëp)
0x80004b2 : movl 0xfffffffc(ëp),êx
0x80004b5 : pushl êx
0x80004b6 : pushl $0x80004f8
0x80004bb : call 0x8000378
0x80004c0 : addl $0x8,%esp
0x80004c3 : movl ëp,%esp
0x80004c5 : popl ëp
0x80004c6 : ret
0x80004c7 : nop
------------------------------------------------------------------

我们看到当function时, RET会是0x8004a8, 我们希望跳过在0x80004ab赋值指令个想要执行指令在0x8004b2 简单计算告诉我们两个指令距离为8字节

  • 篇文章: 有关net.exe跟net1.exe关系

  • 篇文章: 多进程vbs脚本
  • Tags:  mcafee缓冲区溢出 缓冲区溢出漏洞 缓冲区溢出攻击 缓冲区溢出

    延伸阅读

    最新评论

    发表评论