C 声明变量堆栈
我有两个文件名auth_overflow&auth_overflow2,唯一的区别是变量声明的顺序。我的问题是,根据FILO(先进先出),声明序列是否会影响它们的堆栈序列 验证溢出C 声明变量堆栈,c,debugging,variables,gdb,stack,C,Debugging,Variables,Gdb,Stack,我有两个文件名auth_overflow&auth_overflow2,唯一的区别是变量声明的顺序。我的问题是,根据FILO(先进先出),声明序列是否会影响它们的堆栈序列 验证溢出 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
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
交换变量后的预期输出:
(gdb) x/x password_buffer
0xbffff53c: 0x08048330
(gdb) x/x &auth_flag
0xbffff52c: 0x00000000
我在第6行和第7行之间交换了地址,我希望它们相应的地址也能交换。相反,尽管进行了交换,它们的地址仍然保持不变。有什么解释吗?谢谢。在32位机器上,声明顺序会影响其在内存中的位置,不确定64位机器如何处理它,但它会从内存将变量推入寄存器,然后再放入堆栈 假设您使用32位计算机,在这种情况下,必须交换内存位置,您确定在交换后编译了代码吗 验证溢出似乎是正确的,
auth_overflow2应该给出问题中的预期输出,但不确定为什么会这样。我能想到的唯一原因是尝试重新编译代码。变量声明的顺序无关紧要,因为它只是一个声明 当您将变量定义为局部变量(在堆栈上)时,编译器可以在堆栈上分配任何适当的位置,对齐变量并“重新排序”。这实际上不是重新排序,因为只有编译器选择顺序 例如:
int foo(void)
{
int a;
int b;
return a + b;
}
int bar(void)
{
int b;
int a;
return a + b;
}
将由GCC编译为以下汇编程序代码:
[gcc-S——详细的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
.text
.对齐2
.全球食品
.输入foo,%function
傅:
@功能支持互通。
@args=0,假装=0,帧=8
@帧\u needed=1,使用\u匿名\u args=0
@链接寄存器保存已消除。
str fp,[sp,#-4]!@,
添加fp、sp、#0@、,,
副警司,警司#12,,,
ldr r2,[fp,#-8]@tmp136,a
ldr r3,[fp,#-12]@tmp137,b
rsb r3,r3,r2@D.4069,tmp137,tmp136
mov r0,r3@,
添加sp、fp、#0@、,,
ldmfd sp!,{fp}
bx-lr
.尺寸为foo,.-foo
.对齐2
.全球律师协会
.类型栏,%function
酒吧:
@功能支持互通。
@args=0,假装=0,帧=8
@帧\u needed=1,使用\u匿名\u args=0
@链接寄存器保存已消除。
str fp,[sp,#-4]!@,
添加fp、sp、#0@、,,
副警司,警司#12,,,
ldr r2,[fp,#-8]@tmp136,a
ldr r3,[fp,#-12]@tmp137,b
rsb r3,r3,r2@D.4067,tmp137,tmp136
mov r0,r3@,
添加sp、fp、#0@、,,
ldmfd sp!,{fp}
bx-lr
.尺寸条,.-条
如您所见,变量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堆栈保护器
感谢@harper和@tesseract的贡献:-)这取决于编译器和优化器选项。有些编译器会根据大小等因素对堆栈上的局部变量重新排序。您使用的是64位计算机吗?如果是这种情况,堆栈的行为与32位机器略有不同,那么变量将被推入寄存器,然后被推入64位机器上的堆栈。是的,我附加了“list”命令输出,以表明我已经重新编译了代码。交换声明后,我同意交换内存地址。但是它就是不工作。它是64位计算机吗?我只是在我的计算机上运行了溢出和溢出2。我用2个变量制作了一个非常简单的程序,然后交换它们,正如预期的那样,内存位置被交换为auth_overflow2。我使用的是64位mac电脑,因此64位或32位操作系统似乎没有问题。有关您计算机的一些信息可能会有用,因为大多数情况下这些信息取决于编译器和机器体系结构的类型。
bash-4.2$uname-a
Linux darkstar 3.10.17#2 Wed Oct 23 17:46:52 CDT 2013 i686 Intel(R)Core(TM)2个四CPU Q9550@2.83GHz GenuineIntel GNU/Linuxbash-4.2$gcc--version
gcc(gcc)4.8.2如果您所说的是正确的,那么我担心我正在读的书会把我引向错误的方向。仅仅是因为书中提到了交换变量后的内存位置交换。谢谢你澄清我的疑问。大多数答案不是我写的,而是编译器写的。;-)感谢您的澄清,我将继续寻找答案,因为结果因机器类型而异:-)“我对GCC的观察是变量按字母顺序排序。”对于相同大小的变量,这可能是正确的,但我相信大小是第一个排序维度。事实上,我有一个char-test\u数组[16]
和一个int-test\u-int
,并且,无论我如何声明它们,int始终位于堆栈中数组的上方(它们之间的距离始终是4个字节)。我认为,基于非常小的样本大小,您得出的结论不一定正确。编译器可以随意安排局部变量。事实上,局部变量可能根本不在堆栈上表示(使用寄存器),或者如果编译器检测到变量处于活动使用状态的时间没有重叠,则可以将同一位置用于多个局部变量。编译程序
(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