如何让C++编译器忽略缓冲区溢出?为何复现漏洞时输出始终为0x0?
问题背景
用户尝试用以下C++代码演示缓冲区溢出,但遇到两个问题:输入超长内容时程序直接崩溃;关闭编译器错误提示后,输出始终为0x0,溢出未生效。
代码示例:
#include <iostream> using namespace std; constexpr auto INPUT_LENGTH = 4; int bof1(){ int ret_value = 0; char input[INPUT_LENGTH]; int i = 0; do{ input[i] = getchar(); } while(input[i++] != '10'); //enter key return ret_value; } int main(){ cout << "0x" << hex << right << bof1() << endl; }
问题原因与解决办法
1. 代码本身的低级错误
循环条件里的'10'是错误写法!ASCII中的换行符是十进制10,正确写法应为'\n'或直接写10(不带单引号)。'10'属于多字符常量,在C++中行为未定义,会导致循环提前终止,根本没机会往缓冲区中写入足够内容触发溢出。
2. 现代编译器的安全防护机制
当前主流编译器(GCC/Clang/MSVC)默认开启栈保护(Stack Smashing Protection),会在栈帧中插入校验值,一旦缓冲区溢出破坏该值,程序会直接触发崩溃(调用__stack_chk_fail),阻止你修改目标变量或返回地址。
关闭栈保护需在编译时添加对应参数:
- GCC/Clang:
-fno-stack-protector - MSVC:
/GS-
另外,系统默认开启的**地址空间布局随机化(ASLR)**会让栈地址每次运行都变化,导致精准覆盖目标困难,需手动关闭:
- Linux:执行
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space - Windows:可通过调试器或系统设置关闭
3. 栈帧布局与预期不符
代码中ret_value、input、i的栈上位置,可能被编译器调整或添加对齐填充。比如ret_value可能被放在input的高地址区域,而输入内容是从低地址往高地址写入,溢出内容会先覆盖i,无法优先修改ret_value。
查看具体栈布局可生成汇编代码:
- GCC:执行
g++ -S 你的代码文件名.cpp,查看生成的.s文件
4. 调整代码让溢出更容易触发
将ret_value移到input之后(栈上更低地址),溢出内容会优先覆盖它:
#include <iostream> using namespace std; constexpr auto INPUT_LENGTH = 4; int bof1(){ char input[INPUT_LENGTH]; int ret_value = 0; // 现在ret_value在input栈下方,溢出会先覆盖它 int i = 0; do{ input[i] = getchar(); } while(input[i++] != '\n'); // 修正换行符判断 return ret_value; } int main(){ cout << "0x" << hex << right << bof1() << endl; }
用无防护方式编译:
g++ -fno-stack-protector -o bof_demo 你的代码文件名.cpp
(若要演示栈执行代码,可再加-z execstack,仅修改变量时可选)
运行时用十六进制输入工具测试:
printf 'aaaa\x12\x34\x56\x78\n' | ./bof_demo
此时会输出0x78563412(x86为小端序,字节顺序反转),说明ret_value被成功修改,溢出生效。
内容的提问来源于stack exchange,提问作者David D.

