c - C缓冲区溢出的解释

标签 c buffer-overflow

我试图理解缓冲区溢出。这是我的代码:

#include <stdio.h>

int main() 
{
    char buf[5] = { 0 };
    char x = 'u';

    printf("Please enter your name: ");
    gets(buf);

    printf("Hello %s!", buf);

    return 0;
}

buf 数组大小为 5,并用 0es 初始化。所以(空终止)我有四个字符的空间。如果我输入五个字符(例如 stack),我会覆盖空终止字符,printf 应该打印“Hello stacku!”因为后续变量 x。但事实并非如此。它只是打印“堆栈”。有人可以解释一下原因吗?

最佳答案

简短的解释是,仅仅因为您在“buf”之后的源代码行中声明了“x”,并不意味着编译器将它们放在堆栈中并排放置。对于显示的代码,'x' 根本没有被使用,所以它可能没有被放在任何地方。即使您确实以某种方式使用了“x”(并且它必须是一种防止它被塞入寄存器的方法),编译器也很有可能将它排序为 below“buf”它不会被溢出“buf”的代码覆盖。

您可以强制此程序使用 struct 结构覆盖“x”,例如

#include <stdio.h>

int main() 
{
    struct {
        char buf[5];
        char x[2];
    } S = { { 0 }, { 'u' } };

    printf("Please enter your name: ");
    gets(S.buf);

    printf("Hello %s!\n", S.buf);
    printf("S.x[0] = %02x\n", S.x[0]);

    return 0;
}

因为 struct 的字段 总是按照它们在源代码中出现的顺序排列在内存中。1 原则上有可以在 S.bufS.x 之间填充,但是 char 必须有 1 的对齐要求,所以 ABI 可能不需要.

但即使您那样做,它也不会打印“Hello stacku!”,因为gets 总是写入终止NUL。观看:

$ ./a.out 
Please enter your name: stac
Hello stac!
S.x[0] = 75

$ ./a.out 
Please enter your name: stack
Hello stack!
S.x[0] = 00

$ ./a.out 
Please enter your name: stacks
Hello stacks!
S.x[0] = 73

看看它如何始终打印您键入的内容,但是 x[0] 确实被覆盖了,首先是 NUL,然后是 's'?

(您已经阅读了 Smashing the Stack for Fun and Profit 了吗?您应该阅读。)


1 学究脚注:如果涉及位域,则内存中的域顺序将部分由实现定义。但这对于这个问题的目的并不重要。

关于c - C缓冲区溢出的解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52003862/

相关文章:

c# - 如何在混合应用程序中获取有关缓冲区溢出异常的信息?

c++ - "xor eax, ebp"在 C++ 编译器输出中使用

c - 中止陷阱而不是缓冲区溢出

c - API 返回结构

ios - 如何将 Obj-C block 保存在 C 结构中?

c - 将在短路评估中首先执行 (a&&b)

c - 从数组中选取一个随机字符

c++ - 这个缓冲区溢出的后果?

linux - 动态查找shellcode的地址,放置在堆栈上

从 pthread_create 中的函数调用 C 程序