我试图了解缓冲区溢出是如何工作的,所以我正在研究各种简单的例子,涉及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()的返回地址压入de stack,然后存储先前的EBP记录,然后为本地var buffer 分配8个字节,所以为了覆盖RET地址,我应该输入12个字节和预期的RET地址。
但情况并非如此,当我将其加载到GDB中并解散GetInput()时,它会说:
0x080483f4 <+0>: push %ebp
0x080483f5 <+1>: mov %esp,%ebp
0x080483f7 <+3>: sub $0xc,%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个字节的行。
任何人都可以帮我解决这个问题吗?
答案 0 :(得分:2)
我尝试在https://gcc.godbolt.org/中使用不同版本的GCC编译代码。
gcc 4.4.7
and
gcc 4.8.2
GetInput():
pushl %ebp
movl %esp, %ebp
subl $12, %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 $8, %esp
leal -8(%ebp), %eax
pushl %eax <---------------
call gets
addl $4, %esp
leal -8(%ebp), %eax
pushl %eax
call puts
addl $4, %esp
leave
ret
注意缓冲区的地址如何传递给gets(),在GCC 4.4.7和4.8.2中,编译器减去12个字节,地址直接写入堆栈顶部。而对于GCC 4.9.0,只减去了8个字节,需要额外的PUSH。所以,是的,看起来额外的4个字节是缓冲区的地址。