我正在使用 ubuntu 12.04 和 64 位机器。我正在读一本关于缓冲区溢出的好书,在玩一个例子时发现了一个奇怪的时刻。
我有这个非常简单的 C 代码:
void getInput (void){
char array[8];
gets (array);
printf("%s\n", array);
}
main() {
getInput();
return 0;
}
在文件overflow.c
我用 32 位标志编译它,因为书中的所有示例都假定为 32 位机器,我这样做是这样的
gcc -fno-stack-protector -g -m32 -o ./overflow ./overflow.c
在代码中 char 数组只有 8 个字节,但查看反汇编时我发现该数组从堆栈上保存的 EBP 开始 16 个字节,所以我执行了这一行:
printf "aaaaaaaaaaaaaaaaaaaa\x10\x10\x10\x20" | ./overflow
并得到:
aaaaaaaaaaaaaaaaaaaa
Segmentation fault (core dumped)
然后我打开核心文件:
gdb ./overflow core
#0 0x20101010 in ?? ()
(gdb) info registers
eax 0x19 25
ecx 0xffffffff -1
edx 0xf77118b8 -143583048
ebx 0xf770fff4 -143589388
esp 0xffef6370 0xffef6370
ebp 0x61616161 0x61616161
esi 0x0 0
edi 0x0 0
eip 0x20101010 0x20101010
正如你所见,EIP 实际上获得了我想要的新价值。但是当我想输入一些有用的值时,比如 0x08048410
printf "aaaaaaaaaaaaaaaaaaaa\x10\x84\x04\x08" | ./overflow
程序像往常一样崩溃,但是当我试图观察 EIP 寄存器中的值时,会发生一些奇怪的事情:
#0 0xf765be1f in ?? () from /lib/i386-linux-gnu/libc.so.6
(gdb) info registers
eax 0x61616151 1633771857
ecx 0xf77828c4 -143120188
edx 0x1 1
ebx 0xf7780ff4 -143126540
esp 0xff92dffc 0xff92dffc
ebp 0x61616161 0x61616161
esi 0x0 0
edi 0x0 0
eip 0xf765be1f 0xf765be1f
突然 EIP 开始看起来像这个 0xf765be1f,它看起来不像 0x08048410。事实上,我注意到将任何从 0 开始的十六进制值都足以得到这个崩溃的 EIP 值。你知道为什么会发生这种情况吗?是因为我在64位机器上吗?
UPD
评论中的好人要求更多信息,这里是 getInput 函数的反汇编:
(gdb) disas getInput
Dump of assembler code for function getInput:
0x08048404 <+0>: push %ebp
0x08048405 <+1>: mov %esp,%ebp
0x08048407 <+3>: sub $0x28,%esp
0x0804840a <+6>: lea -0x10(%ebp),%eax
0x0804840d <+9>: mov %eax,(%esp)
0x08048410 <+12>: call 0x8048310 <gets@plt>
0x08048415 <+17>: lea -0x10(%ebp),%eax
0x08048418 <+20>: mov %eax,(%esp)
0x0804841b <+23>: call 0x8048320 <puts@plt>
0x08048420 <+28>: leave
0x08048421 <+29>: ret