我的代码如下:
char buffer[10];
void main(int argc, char *argv[]) {
strcpy(buffer, argv[1]);
printf("value of buffer %s\n",buffer);
}
我知道将缓冲区变量放在main函数中我可以溢出堆栈,但是通过将它声明为全局变量,无论我从命令行输入多少ascii字符都没有发生。我期待一个分段错误,但它似乎打印我输入的所有字符。怎么会?
如果程序存在缓冲区溢出漏洞,我还有另一个与该主题相关的问题,例如:如果代码超过为用户程序分配的内存边界,那么我可以在易受攻击的变量中输入一个尽可能大的代码,或者SO会抛出一个分段默认异常吗?
答案 0 :(得分:7)
此代码导致未定义的行为,即您无法预料到分段错误。任何事情都可能发生。
答案 1 :(得分: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);
}
答案 2 :(得分:4)
你正在溢出你的全局变量,只是因为它没有发生任何(显然)坏事。尝试将代码更改为:
char before[20];
char buffer[10];
char after[20];
根据您的工具链如何设置内存,您应该能够在buffer
或before
中看到溢出after
的后果。
您没有获得SEGV的具体原因是,只有当您尝试存储的位置位于操作系统已分配给您的进程的区域之外时,才会出现这种情况。这种分配是在4k单位(通常)上完成的,通常是其中的几个,所以你可能需要至少4kB溢出global
,并且可能需要1MB或更多来触发SEGV。
答案 3 :(得分:1)
全局变量不存储在堆栈中。它们存储在.data / .bss中,并向更高的地址空间增长。堆栈变量朝着较低的地址空间增长。程序指令保持在低于。(.text)而不是.data,因此溢出全局不会覆盖它们所以你不会看到任何明显的事情发生(如seg故障)。
在Linux上无论如何。
答案 4 :(得分:1)
正如其他答案所解释的那样,语言规范使您无权期望任何特定对缓冲区溢出的反应(无论是在全局变量还是本地变量中)。
在实践中会发生的事情是,某些未保留用于buffer
的内存会被覆盖。但是,由于您的程序在printf
之后立即退出,很可能会发生任何使用该内存的内容都没有任何机会发现应该存在的值不再存在。链接器也可能在buffer
之后分配了一堆未使用的空间,例如,如果它将可写数据段的大小四舍五入到4096的倍数或其他一些方便的块大小
答案 5 :(得分:1)
尝试使用更大的输入缓冲区,例如:
./tst $(perl -e "print 'A'x10000")
你最终可能会遇到段错误。
正如一些人在他们的回答中所提到的,写过对象是未定义的行为,任何事情都可能发生。
虽然C不讨论堆栈或堆,但文件范围变量(如程序中的buffer
)通常不会存储在堆栈中。
当缓冲区在堆栈中时,你很快(即,不需要非常大的输入)缓冲区用一些随机地址覆盖函数的返回地址,这就是你在函数返回时得到段错误的原因