gcc是否在编译时重新排序局部变量?

我现在正在阅读(第二次)“黑客:剥削的艺术”并且偶然发现了一些事情。

本书提出了两种不同的方法来利用这两个类似的程序: auth_overflow和auth_overflow2

在第一个中,有一个像这样的密码检查function

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) { 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标志进行编译,但结果是一样的。

你们其中一个人知道为什么会这样吗?

提前致谢。

编译器作者可以完全自由地为具有自动存储的局部变量实现任何分配方案。 auth_flag可以在堆栈上的password_buffer之前或之后设置,它可以在寄存器中,如果对代码进行适当的分析,它可以完全省略。 甚至可能没有堆栈…标准给你的唯一保证是:

strcpy(password_buffer, password); 如果包含其null终止符的源字符串长于目标数组password_buffer则调用未定义的行为。 这种未定义的行为是否符合您的需求完全超出了语言规范。

事实上,一些实现者通过随机化诸如发布代码之类的行为来故意使黑客的任务复杂化。