代码之家  ›  专栏  ›  技术社区  ›  lukasl1991

C缓冲区溢出的解释

  •  3
  • lukasl1991  · 技术社区  · 6 年前

    #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 printf 应该打印“你好,斯塔克!”因为后面的变量 x . 但事实并非如此。它只是打印“stack”。有人能解释一下原因吗?

    3 回复  |  直到 6 年前
        1
  •  2
  •   Tim Randall    6 年前

    局部变量通常在堆栈上创建。在大多数实现中,堆栈向下增长,而不是向上增长,因为内存是分配的。所以,很可能 buf x . 所以,当 溢出,不覆盖 .

    buf[-1]='v';printf("%c\n",x); 尽管这可能会受到填充的影响。将地址与 printf("%i\n",buf - &x); 缓冲器 .

        2
  •  12
  •   zwol    6 年前

    简单的解释是,仅仅因为在“buf”之后的源代码行中声明了“x”,并不意味着编译器将它们放在堆栈中的相邻位置。在代码显示的情况下,'x'根本不用,所以它可能没有被放入 在任何地方 . 即使你确实以某种方式使用了'x'(这必须是一种防止它被塞进寄存器的方法),编译器也很有可能对它进行排序 “buf”就是这样

    struct 构造,例如。

    #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;
    }
    

    因为 1个 原则上 S.buf S.x ,但是 char 必须有1的对齐要求,所以ABI可能不需要。

    但即使你这么做了 那个 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个

        3
  •  6
  •   Steve Summit    6 年前

    正如另一个答案所指出的,这根本不能保证 x 之后马上就坐 buf 在记忆中。但即便如此: gets 得到 无法知道目标缓冲区有多大。(这是它的致命缺陷。)它总是写入它读取的整个字符串,加上终止字符串 \0 . 所以如果 刚好坐在后面 ,然后如果键入五个字符的字符串, printf 可能会正确打印(如您所见),如果您要检查

    printf("x = %d = %c\n", x, x);
    

    它可能会告诉你 现在是0,不是 'U' .

    以下是记忆最初的样子:

         +---+---+---+---+---+
    buf: |   |   |   |   |   |
         +---+---+---+---+---+
    
         +---+
      x: | U |
         +---+
    

         +---+---+---+---+---+
    buf: | s | t | a | c | k |
         +---+---+---+---+---+
    
         +---+
      x: |\0 |
         +---+
    

    如果你要输入“大象”,它会是这样的:

         +---+---+---+---+---+
    buf: | e | l | e | p | h |
         +---+---+---+---+---+
    
         +---+
      x: | a | n   t  \0
         +---+
    

    n , t 可能会导致更多的问题。

    得到 ,永远。不能安全使用。