我有2个文件名称auth_overflow& auth_overflow2,唯一的区别是变量声明的序列。我的问题是,声明序列是否会根据FILO影响其堆栈序列(先后出)?
auth_overflow
bash-4.2$ gdb -q auth_overflow
Reading symbols from /home/reader/hacking/auth_overflow...done.
(gdb) list
5 int check_authetication (char *password) {
6 int auth_flag = 0;
7 char password_buffer[16];
8
9 strcpy(password_buffer, password);
(gdb) break 9
Breakpoint 1 at 0x804850d: file auth_overflow.c, line 9.
(gdb) run AAAAAAAAAAAA
Starting program: /home/reader/hacking/auth_overflow AAAAAAAAAAAA
Breakpoint 1, check_authetication (password=0xbffff7f3 'A' <repeats 12 times>) at auth_overflow.c:9
9 strcpy(password_buffer, password);
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
auth_overflow2
bash-4.2$ gdb -q auth_overflow2
Reading symbols from /home/reader/hacking/auth_overflow2...done.
(gdb) list
5 int check_authetication (char *password) {
6 char password_buffer[16];
7 int auth_flag = 0;
8
9 strcpy(password_buffer, password);
(gdb) break 9
Breakpoint 1 at 0x804850d: file auth_overflow2.c, line 9.
(gdb) run AAAAAAAAAAAA
Starting program: /home/reader/hacking/auth_overflow2 AAAAAAAAAAAA
Breakpoint 1, check_authetication (password=0xbffff7f2 'A' <repeats 12 times>) at auth_overflow2.c:9
9 strcpy(password_buffer, password);
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
正常输出:
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
变量交换后的预期输出:
(gdb) x/x password_buffer
0xbffff53c: 0x08048330
(gdb) x/x &auth_flag
0xbffff52c: 0x00000000
我换了第6行和第6行。 7我希望他们的相应地址也可以交换。相反,尽管交换,他们的地址保持不变。这有什么解释吗?谢谢。
答案 0 :(得分:1)
变量声明的顺序无关紧要,因为它只是一个声明。
当您将变量定义为局部变量(在堆栈上)时,编译器可以在堆栈上分配任何适当的位置,对齐变量并“重新排序”它们。它不是真正的重新排序,因为只有编译器才会选择顺序。
示例:
int foo(void)
{
int a;
int b;
return a + b;
}
int bar(void)
{
int b;
int a;
return a + b;
}
将由GCC编译为此汇编代码: [gcc -S --verbose-asm foo.c]
.text
.align 2
.global foo
.type foo, %function
foo:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]! @,
add fp, sp, #0 @,,
sub sp, sp, #12 @,,
ldr r2, [fp, #-8] @ tmp136, a
ldr r3, [fp, #-12] @ tmp137, b
rsb r3, r3, r2 @ D.4069, tmp137, tmp136
mov r0, r3 @, <retval>
add sp, fp, #0 @,,
ldmfd sp!, {fp}
bx lr
.size foo, .-foo
.align 2
.global bar
.type bar, %function
bar:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]! @,
add fp, sp, #0 @,,
sub sp, sp, #12 @,,
ldr r2, [fp, #-8] @ tmp136, a
ldr r3, [fp, #-12] @ tmp137, b
rsb r3, r3, r2 @ D.4067, tmp137, tmp136
mov r0, r3 @, <retval>
add sp, fp, #0 @,,
ldmfd sp!, {fp}
bx lr
.size bar, .-bar
如您所见,变量a始终位于同一地址[fp-8]
。我对GCC的观察是变量按字母顺序排序。
答案 1 :(得分:1)
根据@harper的汇编输出,编译器可以自由地重新排序变量堆栈,因此在这种情况下,它总是在int变量之前的char数组。这使得程序容易受到基于堆栈的缓冲区溢出的影响。
为了更改以下内容:
(gdb) x/x password_buffer
0xbffff52c: 0x08048330
(gdb) x/x &auth_flag
0xbffff53c: 0x00000000
进入预期产出如下:
(gdb) x/x password_buffer
0xbffff53c: 0x08048330
(gdb) x/x &auth_flag
0xbffff52c: 0x00000000
我们只需在编译期间添加-fstack-protector-all
参数,结果将如预期一样。反之亦然,也许您可以使用-O0
或-fno-stack-protector
。
感谢@harper和@tesseract的贡献: - )
答案 2 :(得分:0)
在32位机器上,声明的顺序会影响它放在内存中的位置,不确定64位机器是如何处理的,但是从内存中它将变量推入寄存器然后再到堆栈。
假设您使用32位机器,在这种情况下必须交换内存位置,您确定在交换后编译代码吗?。
auth_overflow似乎正确, auth_overflow2应该在你的问题中给出预期的输出,不知道为什么会这样。我能想到的唯一原因是尝试重新编译代码。