gcc是否在编译时重新排序局部变量? [英] Is gcc reordering local variables at compilation time?
问题描述
我现在正在阅读(第二次)黑客攻击的艺术,并且偶然发现了一些东西。本书提出了两种不同的方式利用这两个类似的程序: auth_overflow 和 auth_overflow2
在第一个,有一个像这样的密码检查功能
int check_authentication(char * password){
int auth_flag = 0;
char password_buffer [16];
strcpy(password_buffer,password);
...
}
输入16个以上的ASCII字符会改变auth_flag的值大于0,从而绕过检查,如此gdb输出所示:
gdb $ x / 12x $ esp
0xbffff400:0xffffffff 0x0000002f 0xb7e0fd24 0x41414141
0xbffff410:0x41414141 0x41414141 0x41414141 0x00000001
0xbffff420:0x00000002 0xbffff4f4 0xbffff448 0x08048556
password_buffer @ 0xbffff40c
auth_flag @ 0xbffff41c
第二个程序颠倒了两个变量:
int check_authentication(char * password){$ b $ char password_buffer [16];
int auth_flag = 0;
strcpy(password_buffer,password);
...
}
然后笔者建议,溢出到auth_flag,我真的相信。然后我开始溢出缓冲区,令我惊讶的是,它仍然有效。 auth_flag变量仍然在缓冲区之后,就像你在这个gdb输出中看到的那样:
gdb $ x / 12x $ esp
0xbffff400:0xffffffff 0x0000002f 0xb7e0fd24 0x41414141
0xbffff410:0x41414141 0x41414141 0x41414141 0x00000001
0xbffff420:0x00000002 0xbffff4f4 0xbffff448 0x08048556
password_buffer @ 0xbffff40c
auth_flag @ 0xbffff41c
我想知道gcc是不是将局部变量重新排序以用于对齐/优化。
我试着用-O0标志进行编译,但结果是一样的。
您是否知道为什么会发生这种情况?
在此先感谢。
编译器作者完全免费实现具有自动存储的局部变量的任何分配方案。可以在 password_buffer
之前或之后设置 auth_flag
,它可以在寄存器中,它可以完全消失如果适当的代码分析允许它。甚至可能没有堆栈......标准给你的唯一保证是这样的:
$ b
strcpy(password_buffer,password);
password_buffer
,则code>调用未定义的行为。这种未定义的行为是否符合你的需求完全在语言规范之外。事实上,一些实现者故意使得在发布的代码等情况下,这些黑客会随机化。 I'm currently reading (for the second time) "Hacking : The Art of Exploitation" and have stumbled on something.
The book suggests two different ways to exploit these two similar programs : auth_overflow and auth_overflow2
In the first one, there is a password checking function layed out like this
int check_authentication(char *password) {
int auth_flag = 0;
char password_buffer[16];
strcpy(password_buffer, password);
...
}
Inputing more than 16 ASCII characters will change the value of auth_flag to something greater than 0, thus bypassing the check, as shown on this gdb output:
gdb$ x/12x $esp
0xbffff400: 0xffffffff 0x0000002f 0xb7e0fd24 0x41414141
0xbffff410: 0x41414141 0x41414141 0x41414141 0x00000001
0xbffff420: 0x00000002 0xbffff4f4 0xbffff448 0x08048556
password_buffer @ 0xbffff40c
auth_flag @ 0xbffff41c
The second program inverts the two variables :
int check_authentication(char *password) {
char password_buffer[16];
int auth_flag = 0;
strcpy(password_buffer, password);
...
}
The author then suggests than it's not possible to overflow into auth_flag, which I really believed. I then proceeded to overflow the buffer, and to my surprise, it still worked. The auth_flag variable was still sitting after the buffer, as you can see on this gdb output:
gdb$ x/12x $esp
0xbffff400: 0xffffffff 0x0000002f 0xb7e0fd24 0x41414141
0xbffff410: 0x41414141 0x41414141 0x41414141 0x00000001
0xbffff420: 0x00000002 0xbffff4f4 0xbffff448 0x08048556
password_buffer @ 0xbffff40c
auth_flag @ 0xbffff41c
I'm wondering if gcc is not reordering local variables for alignement/optimization purposes.
I tried to compile using -O0 flag, but the result is the same.
Does one of you knows why is this happening ?
Thanks in advance.
The compiler authors are completely free to implement any allocation scheme for local variables with automatic storage. auth_flag
could be set before or after password_buffer
on the stack, it could be in a register, it could be elided completely if proper analysis of the code allows it. There might not even be a stack... The only guarantee the Standard gives you is this:
strcpy(password_buffer, password);
invokes undefined behavior if the source string including its null terminator is longer than the destination array password_buffer
. Whether this undefined behavior fits your needs is completely outside of the language specification.
As a matter of fact, some implementors purposely complicate the task of would be hackers by randomizing the behavior in cases such as the posted code.
这篇关于gcc是否在编译时重新排序局部变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!