声明变量堆栈

我有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' ) 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' ) 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行和第7行之间进行了交换,我希望它们也可以交换相应的地址。 相反,尽管交换,他们的地址仍然相同。 这有什么解释吗? 谢谢。

变量声明的顺序无关紧要,因为它只是一个声明。

当您将变量定义为局部变量(在堆栈上)时,编译器可以在堆栈上分配任何适当的位置,对齐变量并“重新排序”它们。 这不是真正的重新排序,因为只有编译器才会选择顺序。

例:

 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 @,  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 @,  add sp, fp, #0 @,, ldmfd sp!, {fp} bx lr .size bar, .-bar 

如您所见,变量a始终位于同一地址[fp-8] 。 我对GCC的观察是变量按字母顺序排序。

根据@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的贡献:-)

在32位机器上,声明的顺序影响它放在内存中的位置,不确定64位机器如何处理它,但是从内存中它将变量推入寄存器然后到堆栈。

假设您使用32位机器,那么必须交换内存位置,您确定在交换后编译代码吗?

auth_overflow似乎正确,auth_overflow2应该在你的问题中给出预期的输出,不知道为什么会这样。 我能想到的唯一原因是尝试重新编译代码。