获取中...

-

Just a minute...

记录一下有关栈帧的东东

栈帧结构

1
2
3
4
5
6
7
8
9
push ebp                          ;函数开始(使用ebp前先把已有的值保存在栈中)
mov ebp,esp ;保存当前esp到ebp中

;函数体
... ;无论esp如何变化,ebp都保持不变,可以安全访问函数的局部变量,参数

mov esp,ebp ;将函数的起始地址返回到ebp中
pop ebp ;函数返回前弹出保存在栈中的esp的值
retn ;函数终止

示例

1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.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));
return 0;
}

执行main()函数&生成栈帧

int main(int argc,char* argv)

1
push ebp

把ebp的值压入栈,main()函数中,EBP为栈帧指针,用来把ebp的值备份到栈中,main函数执行完毕,返回之前,该值会再次恢复
mov ebp,esp
把esp的值传到ebp,直到main()函数执行完毕,ebp的值始终不变,可以通过ebp安全访问到储存在栈中的函数和局部变量。

设置局部变量

long a=1,b=2;

1
sub esp,8

esp减去8个字节,为函数的局部变量a,b开辟空间,以便它们保存在栈中,,开辟好空间后,main()内部无论esp的值如何变化,变量a和b的栈空间否不会受到破坏。

add()函数参数传递与调用

printf(“%d\n”,add(a,b));

1
2
3
4
5
mov eax,dword ptr ss:[ebp-8]                   ;[ebp-8]=b
push eax ;传参
mov ecx,deord ptr ss:[ebp-4] ;[ebp-4]=a
push ecx ;传参
call 00401000 ;add()

call命令用来调用函数,即add()函数。调用add()函数之前,要先把两个参数压入栈,变量b先入栈,变量a后如栈。进入call命令进入被调用函数之前,先把函数的返回地址压入栈,用作函数执行完毕的返回地址。

开始执行add()函数&生成栈帧

long add(long a,long b)

1
2
push ebp
mov ebp,esp

先把ebp保存到栈中,再把当前的esp储存在ebp中,add()函数内部中的ebp的值始终不变。

设置add()函数的局部变量(x,y)

long x=a,y=b;

1
2
3
4
5
sub esp,8
mov eax,dword ptr ss:[ebp+8] ;[ebp]+8=param a
mov dword ptr ss:[ebp-8],eax ;[ebp-8]=local x
mov ecx,dword ptr ss:[ebp+c] ;[ebp+c]=param b
mov dword ptr ss:[ebp-4],ecx ;[ebp-4]=local y

首先在栈内存中为局部变量x,y开辟一段空间,[ebp+8] [ebp+c]分别指向参数a,b,[ebp-8] [ebp-4]指向add()函数的两个局部变量x,y

add运算

return (x+y);

1
2
mov eax,dword ptr ss:[ebp-8]                 ;[ebp-8]=local x
add eax,dword ptr ss:[ebp-4] ;[ebp-4]=local y

add为加法指令,变量y([ebp-4])与eax原值(x)相加的结果储存在eax中。

删除add()的栈帧&函数执行完毕(返回)

return (x+y);

1
2
3
mov esp,ebp
pop ebp
retn

执加法运算,返回add()函数,在此之前要删除add()的栈帧。把ebp的值赋给esp。
即执行之前用mov ebp,esp命令把函数add()开始执行时的esp的值放入ebp,执行完毕后用mov esp,ebp命令再把储存在ebp的值恢复到esp
pop ebp与push ebp相对应,执行后ebp恢复为main函数的ebp的值,add()函数则被删除

从栈中删除add()函数的参数(整理栈)

1
add esp,8

a,b为长整形,各占4个字节,共8个字节,esp+8则将a,b清除掉

调用printf()函数

printf(“%d\n”,(a,b));

1
2
3
4
push eax                         ;函数add()的返回值
push ******** ;"%d\n"
call ******** ;printf()
add esp,8

esp加上8个字节,将函数的参数从栈中删除

设置返回值

return 0;

1
2
3
mov esp,ebp
pop ebp
retn

main()函数中的栈帧被清除,局部变量a,b不再有效,retn后,主函数执行完毕并返回,之后进行进程终止代码。

相关文章
评论
分享
  • Alloc to Stack&Arbitary Alloc

    Alloc to Stack和Arbitary Alloc都利用了fastbin链表的特性。 Alloc To Stack利用了fastbin链表的特性。当前的chunk的fd指向下一个chunk。Alloc To Stack核心...

    Alloc to Stack&Arbitary Alloc
  • House of Spirit

    House of Spirit针对fastbin,也是fastbin attach的一种。核心在于在目标位置处伪造 fastbin chunk,并将其释放,从而达到分配指定地址的 chunk 的目的。 原理House of Spi...

    House of Spirit
  • Fastbin Double Free

    double free 是任意地址写的一种技巧,指堆上的某块内存被释放后,并没有将指向该堆块的指针清零,那么,我们就可以利用程序的其他部分对该内存进行再次的free, 利用条件Fastbin Double Free 能够成功利用主...

    Fastbin Double Free
Please check the parameter of comment in config.yml of hexo-theme-Annie!