x86_64汇编中的栈平衡(内平栈外平栈)附od反汇编图解


本文结合反汇编pc版植物大战僵尸,讲解游戏暂停后恢复call的过程
在这里插入图片描述

首先介绍栈空间用到的寄存器
ESP 栈顶指针 (extended stack pointer)英文直译是:扩展栈指针
EBP 栈底指针 ,指的是本层call子程序的栈底,就是最上层call的栈底。不是整个栈空间的栈底 (extended base pointer)英文直译是扩展基址指针

push 入栈(给call穿参数)

push eax 等价于 sub esp , 4 mov [esp],eax 把eax压入栈等价于 县 让esp栈指针 - 4 ,然后把 eax的值存入到 esp指向的空间里,也就是栈顶空间里

pop 出栈(call 结束后还原eip)

pop eax 等价于 mov eax,[esp] add esp , 4 把栈里的值出栈给eax 。等价于 先把 esp栈顶指向的空间的值 复制给 eax,然后把栈顶指针 + 4

call调用子程序

call 12345678 等价于 push eip jmp 12345678 pop eip (eip中存储着cpu下一条要执行指令的地址)
例如下面的例子,每次要暂停游戏,以后点击返回游戏以后
执行call之后, eip里面的指,要push到栈顶
在这里插入图片描述
栈顶变成了之前eip里面的值
在这里插入图片描述
下图执行到retn语句的时候栈顶刚好就是call语句执行以后push进来的eip的值。这样cpu执行eip的值,就回到了call的下一条语句
在这里插入图片描述

retn 返回

retn 8 等价于 pop eip , add esp ,8 。先把eip出战,这样cpu再执行的eip的值,就是之前call执行以后,执行的push eip的地址了

栈平衡

内平栈

内平栈的特点是通过retn指令 改变esp,让栈平衡
调用call的时候有函数参数,需要push入栈,retn的时候要把栈顶指针esp还原 加地址
例如当植物大战僵尸每次从暂停以后,再返回游戏,调用了下面的call指令

push edx
call 12345678
return 0x4

调用函数有1个参数,那么就要push 一个参数,这里edx作为第一个参数。 然后call 函数地址。再retn的时候会 retn 0x4 . retn 4等价于 pop eip, add esp 4. 先出栈eip ,让cpu指向调用call前的指令,再 add esp 4,是让栈顶指针 +4 ,就是像栈底移动4,原因是因为在调用call之前,有一个 push edx,这额操作让esp 发生改变,等价于 mov [esp],edx sub esp ,4,让esp减去了4,所以 retn 0x4,让esp再加上4,达到栈平衡
如下图反汇编演示了当植物大战僵尸每次从暂停以后,再点击“”返回游戏“”,调用了下面的call指令,(注意左上角的阳光,我已经改了最大阳光上限,不是9990,而是更大,位数显示不全了)
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

外平栈

外平栈的retn 后面不跟着数字,而是在call结束以后在后面 add esp 直接增加 栈顶指针
如下面例子:

push eax
push ecx
call 12345678
add esp 8

call里面的子程序retn 后面不跟数字

这个add esp 8是让栈顶指针加8,因为call 之前 push了2次,eax和ecx长度都是32位,是4字节 4x2 =8 字节,所以最后加8 字节。

截图如下:
在这里插入图片描述

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值