如何在C语言中利用fgets实现char buffer[2]的缓冲区溢出?
问题代码
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int x; int main(int argc, char **argv) { char buffer[2]; x = 0; puts("please enter text\n"); fgets(buffer, 200, stdin); printf("You have entered: " ); printf( buffer ); printf("\nhidden->%d",x); }
编译参数
gcc -g -O0 -mpreferred-stack-boundary=2 -m32 -fno-stack-protector -z execstack -D_FORTIFY_SOURCE=0 test.c && mv a.out test.o
为什么输入超20字符没触发“预期的溢出”?
你误以为缓冲区溢出会修改全局变量x,但x是全局变量,存储在进程的数据段中,而buffer是栈上的局部变量,栈溢出只会影响栈内存区域,根本碰不到数据段的x,所以即使溢出发生了,x的值也不会变化,你自然看不到预期的“溢出效果”。
另外,栈对齐规则也会影响溢出的触发点:编译时指定了-mpreferred-stack-boundary=2,意味着栈会按4字节(2^2)对齐。char buffer[2]本身只占2字节,但编译器会自动填充2字节凑够4字节的对齐要求,所以buffer在栈上实际占用4字节空间。要覆盖栈上的后续数据(比如EBP寄存器的值、函数返回地址),需要输入超过4字节的内容。
如何验证并实现缓冲区溢出?
修改代码添加栈内变量观察溢出:在
main函数里新增一个栈局部变量,通过它的值变化确认溢出:#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int x; int main(int argc, char **argv) { char buffer[2]; int stack_var = 0x12345678; // 新增栈变量 x = 0; puts("please enter text\n"); fgets(buffer, 200, stdin); printf("You have entered: " ); printf( buffer ); printf("\nhidden->%d",x); printf("\nstack_var->0x%x", stack_var); // 打印栈变量值 }重新编译后输入超过6字节的内容(2字节buffer + 2字节填充 + 4字节stack_var),比如6个
A,就能看到stack_var被修改为0x41414141(ASCII码A对应0x41),证明溢出已发生。触发程序崩溃(覆盖返回地址):输入足够长的字符(比如100个
A),栈上的函数返回地址会被覆盖为非法的0x41414141,程序会触发段错误崩溃,这是缓冲区溢出的典型表现。注意
fgets特性:fgets会读取到换行符或达到指定长度(这里是200),并自动添加\0终止符,实际写入buffer的最大字节数为199,足够覆盖整个栈空间。
内容的提问来源于stack exchange,提问作者hacker man
相关产品推荐
相关产品推荐

