如何让C语言简易缓冲区溢出示例在现代Linux上成功运行?
缓冲区溢出示例测试失败的解决方案请求
问题背景
测试2010年的缓冲区溢出示例未成功,原帖评论区请求澄清无回复。需要可行的精简方案,包括编译选项、操作系统配置、代码修改,以适配现代进程/内存布局,绕过当前系统安全保护。
测试现状
实际输出
$ gcc overflow.c $ ./a.out now inside f()!
预期输出
nils@doofnase:~$ gcc overflow.c nils@doofnase:~$ ./a.out now inside f()! now inside g()! now inside g()! now inside g()! now inside g()! now inside g()! now inside g()! Segmentation fault
测试代码
#include <stdio.h> #include <stdlib.h> void g() { printf("now inside g()!\n"); } void f() { int i; void * buffer[1]; printf("now inside f()!\n"); // can only modify this section // cant call g(), maybe use g (pointer to function) // place the address of g all over the stack: for (i=0; i<10; i++) buffer[i] = (void*) g; // and goodbye... } int main (int argc, char *argv[]) { f(); return 0; }
机器信息
x86_64 GNU/Linux 6.10.9-amd64
可行解决方案
1. 编译时关闭安全保护
现代GCC默认启用栈保护、优化等机制,需通过编译选项关闭:
# 64位编译命令 gcc -fno-stack-protector -O0 overflow.c -o overflow # 若选择32位(栈布局更简单,需系统支持32位库) # gcc -fno-stack-protector -O0 -m32 overflow.c -o overflow
-fno-stack-protector:关闭栈金丝雀(Stack Canary)保护,允许修改返回地址-O0:关闭编译器优化,避免栈变量布局被调整-m32:可选,编译为32位程序,降低栈布局复杂度
2. 调整代码确保覆盖返回地址
原代码中int i在buffer上方,越界写入会先覆盖i的值,导致循环提前终止。将i移到buffer之后,同时增加循环次数,确保覆盖到返回地址区域:
修改后的f()函数:
void f() { void * buffer[1]; int i; // 调整变量顺序,让越界先覆盖返回地址区域 printf("now inside f()!\n"); // 增加循环次数,确保覆盖返回地址 for (i=0; i<20; i++) buffer[i] = (void*) g; }
3. 关闭地址空间随机化(ASLR)
系统默认ASLR会随机化栈地址,导致返回地址位置不固定,测试前临时关闭:
sudo sysctl -w kernel.randomize_va_space=0
测试完成后恢复默认设置:
sudo sysctl -w kernel.randomize_va_space=2
原理说明
现代Linux系统默认启用的安全机制导致原示例失效:
- 栈金丝雀:编译器在栈中插入随机校验值,函数返回前检查,阻止返回地址被修改
- 编译器优化:调整栈变量布局,改变越界写入的覆盖顺序
- ASLR:随机化内存地址,使得返回地址位置无法固定
按照上述步骤操作后,运行./overflow即可得到预期的重复调用g()后触发段错误的结果。
内容的提问来源于stack exchange,提问作者nostromo
相关产品推荐
相关产品推荐

