2012-10-27 61 views
1

我有下面这段代码:为什么我不能溢出一个全局变量?

char buffer[10];  

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

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

我知道放置缓冲区变量主函数里面,我可以使栈溢出,但通过声明它作为一个全局变量,不管我是从多少个ASCII字符输入没有任何反应的命令行。我期待分段错误,但它似乎打印了我输入的所有字符。怎么来的?

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

+0

你用'-Wall'编译了它吗? –

+0

这应该如何帮助? @ shiplu.mokadd.im – alk

+0

好吧,OP缺少'printf()'和'strcpy()'的原型,是的。 – alk

回答

4

您溢满你的全局变量,它只是没有(明显)不好的事情发生,因为它。试着改变你的代码看起来像:

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

根据您的工具链如何勾画出记忆,你应该能够看到无论是beforeafter溢出buffer的后果。

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

+0

你说得对,我试过了: – cracq

+0

我试过了memsetting缓冲区memset(buffer,'a',4000);'什么都没发生。然后我将它改为memset(buffer,'a',5000)',我得到了一个SEGV – cracq

7

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

+2

和“行为像变量被声明为'字符缓冲区[9999]'”是一种有效的“任何事物”。 –

+1

@亨宁马克霍姆什么东西都是有效的。 –

6

尝试follwing 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); 
} 
1

全局变量不存储在堆栈中。它们存储在.data/.bss中,并朝着更高的地址空间发展。堆栈变量朝向较低的地址空间增长。程序指令低于(.text)而不是.data,所以溢出全局不会覆盖它们所以你不会看到任何明显的事情发生(像seg故障)。不管怎么说,我们都可以在Linux上使用这个功能。

1

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

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

1

尝试用较大的输入缓冲器,例如:

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

,你可能会与段错误告终。

正如在他们的答案中提到的一些写过去的对象是未定义的行为,任何事情都可能发生。另外,虽然C没有谈论堆栈或堆,但文件范围变量(如程序中的buffer)通常不会存储在堆栈中。

当缓冲区在堆栈中时,你非常快速(即不需要非常大的输入)缓冲区覆盖函数的返回地址,并带有一些随机地址,这就是当函数返回一个段错误回报。

相关问题