栈帧

栈帧是什么?

利用EBP(栈帧指针)寄存器访问栈内局部变量、参数、函数返回地址等的手段。

为单个过程,一个函数调用分配的那部分栈称为栈帧,一个栈帧的底部由EBP指向,作为在该栈帧内访问所有内容的基准(所有访问地址都以该EBP为准相对偏移),ESP则在移动着,作为该栈帧的顶部。

栈帧的作用是什么?

在程序中用于声明局部变量,调用函数。

在函数调用时,将ESP当前的值保存在EBP中,之后以EBP为基准,访问相关的局部变量、参数、返回地址等,在函数调用结束时,将EBP的值返回给ESP。


(注:在栈中保存函数的返回地址,这是系统存在的一个安全隐患,攻击者使用缓冲区溢出技术可以可以把保存在栈内存的返回地址更改为其他地址。)

下面我们来分析一个实例:

(C源码)

#include<stdio.h>
#include<stdlib.h>
long add(long a, long b)
{
long x = a, y = b;
return (x + y);
}
int main(int argc, char* argv[])
{
long a = 1, b = 2;
printf("%d\n", add(a, b));
system("pause");
return 0;
}

(注:下面所用截图中,灰色阴影部分为下一步将要执行的汇编指令)

1.进入main函数前(图一):


2.进入main,设置好main函数的栈帧(图二):


观察上图,执行PUSH EBP;MOV EBP,ESP后,EBP,ESP的值均为0040FB4C,而观察途中右下区域,可以看到在地址0040FB4C中存储的值为0040FB94(要分清EBP的值和其所指位置中存储的值),这是EBP的初值(看图一可知),它是进入main函数的位置,即main执行完毕后要返回的地址。

3.为main函数中的局部变量a和b分配空间(图三):


SUB ESP,8为a,b分配了八字节的空间,可以看到,该指令下面就是两条MOV指令给分配的位置分别赋上值1,2,这三条指令合在一起就对应了C源码的long a=1,b=2;

4.接下来010310B4~010310BB位置的汇编指令就是将add所用的参数压入栈内(图四),就是调用add的前的状态:


不知道会不会有人困惑,a=1和b=2两个变量都已经在栈内的,为什么还有压栈的操作,这样内存中不是有重复两遍的1,2了吗?

可以这么来理解,假设我们在调用函数add前声明的变量不止a,b两个,而是有很多个变量,add要用的参数仍然是a,b,但是对于计算机来说,程序运行时,他不知道在前面声明的那么多变量中哪一个是a,哪一个是b。他调用函数的方法是结合参数个数,从调用点的位置往前推算的,所以在函数调用前都有参数压入栈的过程,将参数依次逆序入栈存放好,紧接着就要调用函数。

5.调用add(图五):


执行CALL add后,变为上图中的状态,我们看ESP相对于图四中的值-4,存了什么东西进去呢?我们可以看到右下方ESP所指地址0040FB38中存的值为010310C1,这是add函数的返回地址,即main函数中CALL add后一条指令的位置。

6.设置add函数的栈帧(图六):


由上图可以看到EBP的值发生了变化,从main函数的栈帧底部移到了add函数的帧底

7.设置add函数的局部变量x,y(图七):


从汇编指令中我们可以看出,取参数是以add的EBP为基准+XXX,设置变量和前面main函数中分析的一样,用EBP-XXX。

8.add运算完成(图八):


结果是存在EAX中的,在寄存器的部分学习过,EAX可以用于存储函数的返回值,在函数即将返回前,往EAX中存入什么值,该值就会原封不动地返回。

9.删除add栈帧(图九)

从图中可以看出,将ESP回到EBP的位置,然后POP EBP,EBP就回到main函数的帧底位置。下面一条指令RENT,会返回到add函数调用的位置,相当于将当初进入add前存储入栈的返回地址POP出来。

10.整理栈空间,删除函数add的参数(图十):


我们知道add有两个参数,共八个字节,故ADD ESP,8;

下一条指令使PUSH EAX,是将add函数的返回值压入栈中,作为printf的参数,下面接着又是printf的函数调用过程,这里不做赘述了。

自己写个程序放进OllyDbg中单步执行看一遍就会清晰很多~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值