GCC 为局部变量保留了比需要更多的 space
GCC reserving more space than needed for local variables
我想知道缓冲区溢出是如何工作的,所以我正在研究各种简单的例子,涉及 C 和函数 gets() 和 puts()。其中一个程序的源代码如下:
#include<stdio.h>
GetInput()
{
char buffer[8];
gets(buffer);
puts(buffer);
}
main();
{
GetInput();
exit 0;
}
我正在使用以下行进行编译:
gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack demo.c -mpreferred-stack-boundary=2 -g -o demo
GCC版本为4.4.3,32位系统,内核2.6.32
调用GetInput()时,main()的return地址压入de栈,然后存储之前的EBP记录,然后分配8个字节给local var 缓冲区,所以要覆盖RET地址,我应该输入12个字节和预期的RET地址。
但事实并非如此,当我将其加载到 GDB 并分解 GetInput() 时,它表示如下:
0x080483f4 <+0>: push %ebp
0x080483f5 <+1>: mov %esp,%ebp
0x080483f7 <+3>: sub [=13=]xc,%esp <-------
0x080483fa <+6>: lea -0x8(%ebp),%eax
0x080483fd <+9>: mov %eax,(%esp)
0x08048400 <+12>: call 0x804830c <gets@plt>
0x08048405 <+17>: lea -0x8(%ebp),%eax
0x08048408 <+20>: mov %eax,(%esp)
0x0804840b <+23>: call 0x804832c <puts@plt>
0x08048410 <+28>: leave
0x08048411 <+29>: ret
我已经标记了保留 12 个字节而不是 8 个字节的行。
谁能帮我搞定这个?
我尝试在 https://gcc.godbolt.org/ 中使用不同版本的 GCC 编译您的代码。
gcc 4.4.7
and
gcc 4.8.2
GetInput():
pushl %ebp
movl %esp, %ebp
subl , %esp
leal -8(%ebp), %eax
movl %eax, (%esp) <---------
call gets
leal -8(%ebp), %eax
movl %eax, (%esp)
call puts
leave
ret
gcc 4.9.0
GetInput():
pushl %ebp
movl %esp, %ebp
subl , %esp
leal -8(%ebp), %eax
pushl %eax <---------------
call gets
addl , %esp
leal -8(%ebp), %eax
pushl %eax
call puts
addl , %esp
leave
ret
注意缓冲区的地址是如何传递给gets()的,在GCC 4.4.7和4.8.2中,编译器减去12个字节,地址直接写入栈顶。而对于 GCC 4.9.0,只减去了 8 个字节,还需要一个额外的 PUSH。所以,是的,看起来额外的 4 个字节用于缓冲区的地址。
我想知道缓冲区溢出是如何工作的,所以我正在研究各种简单的例子,涉及 C 和函数 gets() 和 puts()。其中一个程序的源代码如下:
#include<stdio.h>
GetInput()
{
char buffer[8];
gets(buffer);
puts(buffer);
}
main();
{
GetInput();
exit 0;
}
我正在使用以下行进行编译:
gcc -fno-stack-protector -D_FORTIFY_SOURCE=0 -z norelro -z execstack demo.c -mpreferred-stack-boundary=2 -g -o demo
GCC版本为4.4.3,32位系统,内核2.6.32
调用GetInput()时,main()的return地址压入de栈,然后存储之前的EBP记录,然后分配8个字节给local var 缓冲区,所以要覆盖RET地址,我应该输入12个字节和预期的RET地址。
但事实并非如此,当我将其加载到 GDB 并分解 GetInput() 时,它表示如下:
0x080483f4 <+0>: push %ebp
0x080483f5 <+1>: mov %esp,%ebp
0x080483f7 <+3>: sub [=13=]xc,%esp <-------
0x080483fa <+6>: lea -0x8(%ebp),%eax
0x080483fd <+9>: mov %eax,(%esp)
0x08048400 <+12>: call 0x804830c <gets@plt>
0x08048405 <+17>: lea -0x8(%ebp),%eax
0x08048408 <+20>: mov %eax,(%esp)
0x0804840b <+23>: call 0x804832c <puts@plt>
0x08048410 <+28>: leave
0x08048411 <+29>: ret
我已经标记了保留 12 个字节而不是 8 个字节的行。
谁能帮我搞定这个?
我尝试在 https://gcc.godbolt.org/ 中使用不同版本的 GCC 编译您的代码。
gcc 4.4.7
and
gcc 4.8.2
GetInput():
pushl %ebp
movl %esp, %ebp
subl , %esp
leal -8(%ebp), %eax
movl %eax, (%esp) <---------
call gets
leal -8(%ebp), %eax
movl %eax, (%esp)
call puts
leave
ret
gcc 4.9.0
GetInput():
pushl %ebp
movl %esp, %ebp
subl , %esp
leal -8(%ebp), %eax
pushl %eax <---------------
call gets
addl , %esp
leal -8(%ebp), %eax
pushl %eax
call puts
addl , %esp
leave
ret
注意缓冲区的地址是如何传递给gets()的,在GCC 4.4.7和4.8.2中,编译器减去12个字节,地址直接写入栈顶。而对于 GCC 4.9.0,只减去了 8 个字节,还需要一个额外的 PUSH。所以,是的,看起来额外的 4 个字节用于缓冲区的地址。