【PWN】ret2text 中「该跳 func 还是 call func?」的困惑解析
摘要:32位ret2text/ret2libc攻击中,调用有参函数时需注意call指令的栈布局影响。研究发现,直接跳转至函数地址会导致异常,而跳转到call指令地址则能正常获取参数。这是因为call指令会先将返回地址压栈(push return_address + jmp func),改变了栈结构。正确栈布局应为:填充数据+目标函数地址+伪造返回地址+参数。在编写exp时应采用"函数地址
·
背景
前两天在学习ret2text时,尤其是在文章:HappyNewYearCTF_5_ret2text 32位中,有提到为什么必须call func才能执行,而将eip直接改为func无法执行。
最初经过分析,误认为是传参,进而导致的栈重建。经过不断细细学习,琢磨,最终发现并非如此。
32位程序
在 32 位 ret2text / ret2libc 场景中,遇到了一个看似矛盾的现象:
- 无参函数:
- 直接把
EIP覆盖为func的地址,一切正常
- 直接把
- 有参函数:
- × 直接跳
func会异常 - √ 反而跳到
call func的地址,函数就“能正常拿到参数”
- × 直接跳
究其根源,实际上是call做了一步将下一步执行内容地址压栈的处理,即如下操作
call func
^
|
push return_address
jmp func
那在这个操作中,其实影响了栈的布局,原本我们认为的布局应该是下面的样子,也就是call system,然后直接读取参数。非常符合我们的直觉。
High
Address | |
+-----------------+ <-- ebp + 8
| 0x0804C028 | 4字节 (/bin/sh字符串位置)
+-----------------+ <-- ebp + 4
| 0x0804925A | 4字节 (system函数的入口地址)
+-----------------+
| ...... | <-- 。。。
+-----------------+
| buf[2] |
| buf[1] | <-- 3字节 (原始缓冲区,溢出起点)
| buf[0] |
+-----------------+
Low | |
Address
但实际场景中,call system其实际操作会进行压栈,也就是压入返回地址。
如果不涉及到call的话,那我们的栈布局应该是下面这样。
High
Address | |
+-----------------+ <-- ebp + 12
| 0x0804C028 | 4字节 (/bin/sh字符串位置)
+-----------------+ <-- ebp + 8
| 0xDEADBEEF | 4字节 (返回地址-无效字符串即可)
+-----------------+ <-- ebp + 4
| 0x0804925A | 4字节 (system函数的入口地址)
+-----------------+
| ...... | <-- 。。。
+-----------------+
| buf[2] |
| buf[1] | <-- 3字节 (原始缓冲区,溢出起点)
| buf[0] |
+-----------------+
Low | |
Address
总结
在进行32位exp编写时,优先还是选择直接进行栈布局,也就是函数地址+返回地址+参数,即:
padding
target_func_addr
fake_ret_addr
[arg1]
[arg2]
[arg3]
更多推荐


所有评论(0)