ROP的一些疑惑

之前对于ROP有点疑惑,现在似乎清楚一些了
https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=0&id=5055&page=1

payload:

from pwn import *
context.update(arch='i386')

p = remote('111.198.29.45',30411)
e = ELF('./level2')

p.sendlineafter(':',flat(['a'*0x8c,e.plt['system'],0,0x804A024,0,0]))
p.interactive()

萌新写篇文章记录一下
正常的的函数func都会有函数序言:push ebp,mov ebp,esp.
这里就会将ebp保存下来,此时的func的栈帧esp=ebp,一般都会sub esp一下抬高栈顶。

而call一般会push eip(伪代码),所以此时栈帧是这样的:

这里的payload:刚好0x88填充到ebp-0x4,多出的四个字节填充ebp(总计0x8c个字符),接下来就是system的返回地址。
这样这个函数执行完之后,会立马跳转到system去
函数结尾一般都会pop ebp,但是由于这里的ebp被覆盖掉了(变成了未知值AAAA),所以当时一直没搞懂,到system函数去了之后会怎样访问接在后面的参数。

后面模拟了一下程序,发现进入system时按道理会:mov ebp,esp所以此时的ebp和之前的在func函数下栈帧中的一样,所以可以访问到后面的参数。
但是system函数返回后,pop ebp,就会将AAAA再次赋予ebp,当返回到main函数时ebp就彻底烂掉了。

总结

所以总结一下,这道题具体情况是这样的:
进去func: push ebp —> mov ebp esp
读入后: push ebp保存的ebp被修改,栈中保存eip的值被修改为system的地址
func返回: pop ebp,此时ebp寄存器的值也被改为覆盖的值,retn返回到system函数体内
进入system: push ebp —>mov ebp esp,此时函数ebp=esp,即等于刚进入func时的ebp的值的情况,那么下面+0x4的位置时system返回地址,+0x8就是第一个参数的位置
system返回: 从栈中取处原先保存的ebp和eip的值,则ebp和eip都修改为了覆盖的值

还有一个小问题,这个p32(0)为什么就成为返回地址的填充了呢
由于在func返回时(执行retn),eip从栈中取出,那么esp必定降低了,当进入system时
mov ebp,esp,ebp所对应的位置也降低了,所以返回地址也从之前的p32(system)下降到了后面的p32(0)了

retn操作:先eip=esp,然后esp=esp+4
retn N操作:先eip=esp,然后esp=esp+4+N

补充

还有关于利用gadget修改寄存器的操作,这种一般都是"gadget地址"+“要修改寄存器的值”+“下一个地址”
这里的流程是:
原函数返回–>程序指向gadget地址–>这个地址出栈–>进入gadget–>从中pop,寄存器值被修改,栈中值出栈–>返回地址

但是在这里的ebp已经被修改了,所以进入下一个函数时的栈已经无法访问参数了

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值