在主要功能中:
0x08049230 <+0>: push %ebp
0x08049231 <+1>: mov %esp,%ebp
0x08049233 <+3>: sub $0x28,%esp
0x08049236 <+6>: movl $0xdeadbeef,-0xc(%ebp)
0x0804923d <+13>: call 0x8048ed4 <getbuf>
0x08049242 <+18>: mov -0xc(%ebp),%edx
在getbuf函数中:
0x08048ed4 <+0>: push %ebp
0x08048ed5 <+1>: mov %esp,%ebp
0x08048ed7 <+3>: sub $0x28,%esp
0x08048eda <+6>: lea -0x14(%ebp),%eax
0x08048edd <+9>: mov %eax,(%esp)
0x08048ee0 <+12>: call 0x8048de4 <Gets>
0x08048ee5 <+17>: mov $0x1,%eax
0x08048eea <+22>: leave
0x08048eeb <+23>: ret
基本上主要功能使用%ebp-0xc来检查损坏的堆栈。
在getbuf函数中,lea -0x14(%ebp),%eax为输入字符串分配20个字节。
如果我提供24个字节,则会覆盖$ ebp。我不确定为什么getbuf中ebp的变化会影响main函数中的ebp值。
我知道$ ebp会进入堆栈。当getbuf返回时,$ ebp将从堆栈中弹出。 main函数的$ ebp是否从getbuf接收$ ebp?
我也做过一些测试。我的输入字符串是aaaabbbbccccddddeeee,它是24个字节。我在0x08049242&lt; + 18&gt;设置了一个断点:mov -0xc(%ebp),%edx,我打印$ ebp,但是这不是eeee的十六进制表示。我注意到存储在$ ebp中的值确实发生了变化。如果输入小于20字节,则值为0xbffff6c8。如果输入是24个字节,则其值变为0xb7fd0ac0。
任何人都可以解释它是如何变化的,主函数中的$ ebp如何知道gebuf函数中$ ebp的值?
谢谢
答案 0 :(得分:1)
寄存器只有一个副本(每个线程)。函数调用和返回不会根据返回地址的要求更改除esp
之外的寄存器。推送和弹出ebp
的关键是为呼叫者保留它。因此,如果您覆盖堆栈上保存的值,则会将错误的值弹回ebp
并返回给调用者。
我的输入字符串是
aaaabbbbccccddddeeee
,这是24个字节。
不,那是20个字节,加上一个终止零。这仍然会溢出缓冲区,并导致ebp
的低字节被清零。请注意,如果您使用长度为24的字符串,例如aaaabbbbccccddddeeeeffff
,则会将ebp
覆盖为ffff
,其中0x66666666
为十六进制,但终止零将覆盖低位返回地址的字节,所以你甚至不会回到正确的地方。您可以使用长度为23的字符串,例如aaaabbbbccccddddeeeefff
,在这种情况下,ebp
应为0x00666666
:
Starting program: /tmp/a.out
aaaabbbbccccddddeeeefff
Program received signal SIGSEGV, Segmentation fault.
8 mov -0xc(%ebp),%edx
(gdb) p/a $ebp
$6 = 0x666666