gcc 是否在编译时重新排序局部变量?
Is gcc reordering local variables at compilation time?
我目前正在(第二次)阅读 "Hacking : The Art of Exploitation" 并且偶然发现了一些东西。
这本书提出了两种不同的方法来利用这两个相似的程序:auth_overflow and 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) {
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 是否没有出于 alignement/optimization 目的重新排序局部变量。
我尝试使用 -O0 标志进行编译,但结果是一样的。
你们中有人知道为什么会这样吗?
提前致谢。
编译器作者完全可以自由地为具有自动存储的局部变量实现任何分配方案。 auth_flag
可以在堆栈上的 password_buffer
之前或之后设置,它可以在寄存器中,如果对代码的适当分析允许的话,它可以完全省略。甚至可能没有堆栈......标准给你的唯一保证是:
如果包含空终止符的源字符串比目标数组 password_buffer
长,strcpy(password_buffer, password);
会调用未定义的行为。这种未定义的行为是否符合您的需要完全超出了语言规范。
事实上,一些实施者故意通过在发布的代码等情况下随机化行为来使黑客的任务复杂化。
我遇到了同样的问题。为了解决这个问题,将这两个变量放在一个结构中。在结构中,字段始终位于结构中定义的位置。请注意,顺序是相反的。
struct myStruct {
int auth_flag;
char password_buffer[16];
};
我知道这是个老问题了。
但在我的例子中,-fno-stack-protector 标志起到了作用。
因此,如果我使用 -fno-stack-protector 进行编译,则局部变量按例外顺序排序(至少对于这个简单程序而言)。
我想知道,也许重新排序可以起到某种保护作用。
Here I found link about that
我目前正在(第二次)阅读 "Hacking : The Art of Exploitation" 并且偶然发现了一些东西。
这本书提出了两种不同的方法来利用这两个相似的程序:auth_overflow and 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) {
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 是否没有出于 alignement/optimization 目的重新排序局部变量。
我尝试使用 -O0 标志进行编译,但结果是一样的。
你们中有人知道为什么会这样吗?
提前致谢。
编译器作者完全可以自由地为具有自动存储的局部变量实现任何分配方案。 auth_flag
可以在堆栈上的 password_buffer
之前或之后设置,它可以在寄存器中,如果对代码的适当分析允许的话,它可以完全省略。甚至可能没有堆栈......标准给你的唯一保证是:
password_buffer
长,strcpy(password_buffer, password);
会调用未定义的行为。这种未定义的行为是否符合您的需要完全超出了语言规范。
事实上,一些实施者故意通过在发布的代码等情况下随机化行为来使黑客的任务复杂化。
我遇到了同样的问题。为了解决这个问题,将这两个变量放在一个结构中。在结构中,字段始终位于结构中定义的位置。请注意,顺序是相反的。
struct myStruct {
int auth_flag;
char password_buffer[16];
};
我知道这是个老问题了。
但在我的例子中,-fno-stack-protector 标志起到了作用。 因此,如果我使用 -fno-stack-protector 进行编译,则局部变量按例外顺序排序(至少对于这个简单程序而言)。
我想知道,也许重新排序可以起到某种保护作用。 Here I found link about that