函数调用过程内存堆栈变化分析

函数说明,简单函数调用代码如下:

代码:

  

这里我们重复调用了这个函数,来分析编译器传递参数的过程。

我们通过PUSH将一个字符压入堆栈,这个相当于我们c函数传入的参数,然后通过call,调用一个汇编定义的函数,函数里面通过MOV将字符参数装入CL,并且输出到串口。

1.  加载编译好的系统镜像,代码调转到此处,如下图,我们可以看到反编译的系统代码。

 

 

2.       单步运行PUSH B’,然后查看当前段寄存器和通用寄存器。弱弱的补充一下raxeax64位扩展,eaxax32位扩展。这里的r都可以忽略。我们可以看到当前堆栈段寄存器地址是SS=0x8。段顶指针寄存器SP=0x400fffc,段基址是0x1fff0000。我们通过x命令打印堆栈里面的20个字节用16进制表示,这个20字节从段顶开始偏向段基址。

我们可以看到从段顶开始两个字节是0x0042,这个就是我们压入堆栈的‘B,它被存在偏移地址0x400fffc-0x400fffd这个地方。之后数据都是0

3. 继续单步调式,我们进入调用的函数,通过u我们察看当前代码后面的10条反汇编指令,可以看到我们已经进入到打印函数内部第一条语句。这条语句MOV CLbyte ptr ss:[esp+4]就是将我们刚刚压入堆栈的参数得到,然后赋值给cl寄存器。Esp+4的目的就是掉过调用call指令自动压入堆栈的CSIP的值。接着来看这些值。

 

 

4.       接着我们继续打印当前寄存器,结果如下图。从这个图我们可以发现,段顶指针已经从0x400fffc移动到了0x400fff8,然后通过x命令,查看当前堆栈里面的数据,我们可以发现有四个字节的新数据被压入了进来分别是0x65d0 0x0000.对了,这两个值就是我们调用CALL指令的时候自动压入的IPCS,它们分别是CALL后面一条指令的程序偏移地址,和代码段地址。从前面的截图我们可以推算到这个0x65d0就是偏移地址IP,但是为什么这个代码段地址是0呢,当前代码段明明是CS=0x60,那是因为调用的是本段函数,所以这里的CS=0,表示不进行段间调转。所以只需要偏移地址。到目前为止我们可以看到我们一共有8个字节的数据被压入堆栈:4个字节参数,2个字节IP2个字节CS。到这里就可以理解那个ESP+4就是要掉过4个字节的IPCS,取得参数。

 

 

5.       设置断点直接掉到函数结尾ret 0x4。这条指令表示返回时候返回IP,并且清除4个字节压入堆栈的数据。这样说明堆栈内数据要被相当于pop8个字节。

 

6.       执行ret 4.代码走到下一个CALL,这时候我们可以看到当前指令地址是0x60:0xb5d0,这个0xb5d0就是我们刚刚压入堆栈的下一条指令的IP。接下来我们再来看看堆栈。

 

7.       我们可以看到,这个时候Sp已经移动到了0x4010000,这样看来比调用函数之前的0x400fffc要增加了4个字节,这个说明在函数返回的时候,不仅返回了IP,CS的四个字节,系统还清除了ret指定的4个字节,也就是说,调用函数之前允许最多押送4个字节进入堆栈作为参数使用。这样也相当于重新清空了堆栈,我们可以看到新的堆栈顶部以下都没有东西了。全是0

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值