因为要保持栈的大小,使ESP始终指向栈顶
函数压入栈中时的地址
//ESP 为 NN
push p2 //ESP=NN-4
push p1 //ESP=NN-8
call test //ESP=NN-0C
{ //进入函数内
push ebp //ESP=NN-10
mov ebp, esp //EBP 指向 栈顶 EBP==当前ESP
mov eax, dword ptr [ebp+0ch] //eax = 参数2
mov ebx, dword ptr [ebp+08h] //ebx = 参数1
sub esp, 8 //ESP == NN-18
...
add esp, 8 //ESP== NN-10
pop ebp //ESP==NN - C
ret 8 //ESP==NN + 4 +8
}
//ESP = NN
也就是说当函数在栈中操作时,需要先把ESP
转交给EBP
,然后继续操作,当操作完后,在ret
之前,要先将ESP
恢复成进入栈前的状态(进入栈后每次压入参数都会使栈空间一点点变小,而因为ESP要始终指向栈顶的原因,所以要把它恢复成原来的大小。)最后再将EBP
移除栈,这样就是一个简单的栈平衡。
劫持栈的rsp(esp),使其指向其他位置,形成一个伪造的栈。这样栈也就被劫持到攻击者控制的内存上去,然后在该位置做ROP。
pop EBP;ret
: 释放EBP,并链接伪造的栈
leave;ret
: 更改ESP,指向后续的payload
mov ESP,EBP; pop EBP; ret;
栈转移的原理就是以 pop ebp;ret + 伪造的栈
让程序直接跳转到伪造的栈里面,然后为了保持栈平衡,从而执行leave; ret
,最后继续执行伪造的栈内的payload
pop ebp;ret
来调整EBP寄存器pop ebp;ret
可以使用pop EBX;ret
来代替leave;ret
来更改ESP
,使其指向伪造的栈(bss)read/write
时,系统内的dl_fixup函数对stack做了很好的保护bss+0x800
左右参考链接:
https://darkwing.moe/2019/04/15/Pwn学习笔记14-stack-pivot与Off-by-one/