简单栈迁移
简单的栈迁移
小记一下栈迁移的手段,老是忘记。
先介绍一些函数调用过程中的主要指令
- push:栈顶指针ESP减小4个字节;以字节为单位将寄存器数据(四字节,不足补零)压入堆栈,从高到低按字节依次将数据存入ESP-1、ESP-2、ESP-3、ESP-4指向的地址单元。
- pop出栈:栈顶指针ESP指向的栈中数据被取回到寄存器;栈顶指针ESP增加4个字节。
- call:将当前的指令指针EIP(该指针指向紧接在call指令后的下条指令)压入堆栈,以备返回时能恢复执行下条指令;然后设置EIP指向被调函数代码开始处,以跳转到被调函数的入口地址执行。
- leave:恢复主调函数的栈帧以准备返回。等价于指令序列movl %ebp, %esp(恢复原ESP值,指向被调函数栈帧开始处)和popl %ebp(恢复原ebp的值,即主调函数帧基指针)。
- ret:与call指令配合,用于从函数或过程返回。从栈顶弹出返回地址(之前call指令保存的下条指令地址)到EIP寄存器中,程序转到该地址处继续执行(此时ESP指向进入函数时的第一个参数)。若带立即数,ESP再加立即数(丢弃一些在执行call前入栈的参数)。使用该指令前,应使当前栈顶指针所指向位置的内容正好是先前call指令保存的返回地址。
函数的入口点与出口点的基本操作
入口点
1
2push ebp # 将ebp压栈
mov ebp, esp #将esp的值赋给ebp出口点
1
2leave
ret #pop eip,弹出栈顶元素作为程序下一个执行地址其中 leave 指令相当于
1 | mov esp, ebp # 将ebp的值赋给esp |
例题:BUU [Black Watch 入群题]
1 | #coding=utf-8 |
- 结合上面的解释,来理解程序最后的执行流程
- 程序第一次read到bss段上去,我们在bss上部署了payload=p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
- 第二次输入的时候我们将ebp位置填充为bss-4的位置(因为最后leave;ret过去的时候,eps指向了bss+4的位置),所以有payload=’a’*0x18+p32(bss-4)+p32(leave_ret)
- 前两次输入来构造泄露libc
- 第三次输入在bss上构造system调用
- 第四次输入跳转执行system(“/bin/sh”)
64位下类似,但是存在前六个参数寄存器传参的问题。
参考文章
补充一个题目vnctf2022(clear_got)
题目情况
存在一个栈溢出,但是在栈溢出后将memset后面的got全部清零了。
给了两个系统调用
exp
1 | from pwn import * |
- 本文标题:简单栈迁移
- 本文作者:LOLOLO
- 创建时间:2022-02-08 10:46:31
- 本文链接:https://lololo-pwn.github.io/2022/02/08/简单栈迁移/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
评论