1

我在下面有这段代码:

char buffer[10];      

void main(int argc, char *argv[]) {

   strcpy(buffer, argv[1]);
   printf("value of buffer %s\n",buffer);
}

我知道将缓冲区变量放在主函数中可能会使堆栈溢出,但是通过将其声明为全局变量,无论我从命令行输入多少 ascii 字符,都不会发生任何事情。我期待一个分段错误,但它似乎打印了我输入的所有字符。怎么会?

我还有一个与该主题相关的问题,如果程序存在缓冲区溢出漏洞,例如堆栈溢出,我是否可以在易受攻击的变量中输入我想要的代码,或者如果代码超过了 SO 会抛出分段默认异常为用户程序分配的内存边界?

4

6 回答 6

7

此代码会导致未定义的行为,您不能期望出现分段错误。任何事情都有可能发生。

于 2012-10-27T16:12:02.367 回答
6

尝试以下 mod 以查看一些副作用:

char buffer[10];      
char buffer1[10] = "123456789";      

void main(int argc, char *argv[]) {

   strcpy(buffer, argv[1]);
   printf("value of buffer %s\n",buffer);
   printf("value of buffer1 %s\n",buffer1);
}
于 2012-10-27T16:14:34.863 回答
4

你溢出了你的全局变量,只是因为它没有(显然)坏事发生。尝试将您的代码更改为如下所示:

char before[20];
char buffer[10];
char after[20];

根据您的工具链如何布置内存,您应该能够看到bufferbefore或中溢出的后果after

您没有获得 SEGV 的具体原因是,只有当您尝试存储的位置位于操作系统分配给您的进程的区域之外时,才会发生这种情况。此分配是在 4k 单元(通常)上完成的,通常是其中几个单元,因此您可能必须溢出global至少 4kB,并且可能需要溢出 1MB 或更多才能触发 SEGV。

于 2012-10-27T16:16:36.873 回答
1

全局变量不存储在堆栈中。它们存储在 .data/.bss 中,并向更高的地址空间增长。堆栈变量向较低的地址空间增长。程序指令(在 .text 中)比 .data 低,所以溢出全局不会覆盖它们所以你不会看到任何明显的事情发生(比如 seg 错误)。

反正在linux上。

于 2012-10-27T16:17:46.547 回答
1

正如其他答案所解释的那样,语言规范使您无权期望对缓冲区溢出有任何特定反应(无论是在全局变量中还是在本地变量中)。

在实践中发生的情况是,一些未被保留用于使用的内存buffer确实被覆盖了。但是,由于您的程序在您的 之后立即退出printf,因此很可能使用该内存的任何东西都没有机会注意到应该存在的值不再存在。链接器也有可能在 之后分配了一堆未使用的空间buffer,例如,如果它将可写数据段的大小四舍五入为 4096 的倍数或其他一些方便的块大小。

于 2012-10-27T16:18:58.237 回答
1

尝试使用更大的输入缓冲区,例如:

 ./tst $(perl -e "print 'A'x10000")

你可能最终会遇到段错误。

正如一些人在他们的答案中提到的那样,过去的对象是未定义的行为,任何事情都可能发生。

此外,虽然 C 不谈论堆栈或堆,但文件范围变量(如buffer在您的程序中)通常不存储在堆栈中。

当缓冲区在堆栈中时,您会很快(即,不需要非常大的输入)缓冲区用一些随机地址覆盖函数的返回地址,这就是函数返回时出现段错误的原因。

于 2012-10-27T16:23:09.077 回答