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

rge*_*han 9 c gcc gdb reverse-engineering buffer-overflow

我现在正在阅读(第二次)"黑客攻击的艺术",并且偶然发现了一些事情.

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

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

int check_authentication(char *password) {
    int auth_flag = 0;
    char password_buffer[16];

    strcpy(password_buffer, password);
    ...
}
Run Code Online (Sandbox Code Playgroud)

输入超过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
Run Code Online (Sandbox Code Playgroud)

第二个程序反转了两个变量:

int check_authentication(char *password) {
    char password_buffer[16];
    int auth_flag = 0;

    strcpy(password_buffer, password);
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后作者建议,不可能溢出到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
Run Code Online (Sandbox Code Playgroud)

我想知道gcc是否没有重新排序局部变量用于对齐/优化目的.

我尝试使用-O0标志进行编译,但结果是一样的.

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

提前致谢.

chq*_*lie 11

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

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

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