堆栈粉碎保护和缓冲区溢出的问题

Ren*_*ato 3 c security gcc buffer-overflow

我正在做一些关于缓冲区溢出的研究,我想知道堆栈粉碎保护是如何工作的

我有这个代码:

int main( )
{ 
    char Buf[16];
    printf(“Digite o seu nome: ”);
    gets(Buf);
    printf(“%s”,Buf);
return 0;
} 
Run Code Online (Sandbox Code Playgroud)

我用gcc编译它

然后我放入一堆字符来填充缓冲区

首先我放16个字符

$ ./Exemplo1

Digite o seu nome:AAAAAAAAAAAAAAAA

Ola AAAAAAAAAAAAAAAA

这是好的,因为缓冲区大小合适

接下来我尝试24个字符

$ ./Exemplo1

Digite o seu nome:AAAAAAAAAAAAAAAAAAAAAAAA

Ola AAAAAAAAAAAAAAAAAAAAAAAA

为什么它仍然有效?

这不应该导致程序终止!?

它只会在我放入25个或更多字符时终止程序

./Exemplo1

Digite o seu nome:AAAAAAAAAAAAAAAAAAAAAAAAA

Ola AAAAAAAAAAAAAAAAAAAAAAAAA

*堆栈粉碎检测*:./ .Exmplo1终止

为什么?什么是缓冲区后不是返回地址?我读到的以及我认为理解的是它应该有一个金丝雀值,但如果该值已经改变并且将24个字符写入缓冲区它应该终止程序它应该不会给我一个堆栈粉碎检测甚至如果返回地址没有改变但金丝雀值没有改变.

谢谢.

NPE*_*NPE 6

从我对生成的程序集的简要介绍,我认为这是发生的事情(64位Ubuntu上的gcc 4.4.5).

金丝雀是双字(8字节).堆栈 - 包括金丝雀 - 以16字节为增量增长.金丝雀正好位于堆叠框架的末端.要同时满足所有三个要求,gcc可能需要在自动变量和金丝雀之间插入填充.

因为在你的代码中Buf长度为16个gcc字节,Buf所以在金丝雀和金丝雀之间放置8个字节的填充(为了使堆栈帧的大小为16个字节的倍数而需要).这解释了为什么在不触发堆栈粉碎检测的情况下最多可以输入24个字符.

如果我改为Buf8字节长,则不再需要任何填充,输入9个字符会触发保护:

#include <stdio.h>

int main( )
{ 
    char Buf[8];
    printf("Digite o seu nome: ");
    gets(Buf);
    printf("%s",Buf);
    return 0;
 }

aix@aix:~$ ./a.out 
Digite o seu nome: AAAAAAAA
AAAAAAAA

aix@aix:~$ ./a.out 
Digite o seu nome: AAAAAAAAA
*** stack smashing detected ***: ./a.out terminated
Run Code Online (Sandbox Code Playgroud)

显然,这取决于编译器,硬件平台,编译器标志等.

不言而喻,人们不应期望这种机制是防弹的.

如果您想进一步尝试,请尝试使用不同的缓冲区大小编译代码-fno-stack-protector.如果您使用-S生成汇编代码,您将能够在调整设置时看到生成的代码如何更改.