You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 09:05:24