1. 什么是栈溢出?
栈溢出(Stack Overflow)是一种典型的内存漏洞,发生在程序向栈中写入超出其分配空间的数据,导致覆盖栈中的其他数据。
2. 栈的基本概念
栈是计算机内存中的一种数据结构,遵循 LIFO(Last In, First Out) 规则。
2.1 栈的结构
栈通常包括以下几个部分:
-
栈帧(Stack Frame):每个函数调用都会创建一个新的栈帧。
-
返回地址(Return Address):存储函数返回时跳转的地址。
-
局部变量(Local Variables):函数内定义的变量。
-
函数参数(Function Arguments):传递给函数的参数。
2.2 栈的增长方向
在 x86 架构中,栈从高地址向低地址增长,即 ESP
(栈指针)向下移动。
3. 栈溢出的原理
当程序写入超过预期的缓冲区大小时,可能会覆盖返回地址,导致程序执行任意代码。
3.1 栈溢出的示例
#include <stdio.h> #include <string.h> void vulnerable_function(char *input) { char buffer[64]; strcpy(buffer, input); // 无边界检查,存在栈溢出风险 } int main(int argc, char *argv[]) { if (argc > 1) { vulnerable_function(argv[1]); } return 0; }
4. 栈溢出的调试
使用 gdb
调试程序,观察溢出发生的情况。
4.1 编译程序(关闭保护机制)
gcc -fno-stack-protector -z execstack -o vuln vuln.c
4.2 在 GDB 中运行
gdb ./vuln (gdb) run $(python3 -c 'print("A"*80)')
4.3 观察崩溃点
使用 info registers
命令检查 EIP
是否被覆盖。
5. 练习题
-
修改示例代码,使其支持输入更长的字符串,并观察溢出的影响。
-
使用
gdb
进行调试,并尝试找到覆盖EIP
的偏移量。 -
通过
pattern_create
和pattern_offset
工具找到精确的返回地址覆盖位置。
6. 总结
-
了解栈的基本结构及其工作方式。
-
理解栈溢出的原理和风险。
-
通过 GDB 进行栈溢出调试。
-
为后续利用栈溢出进行代码注入奠定基础。