首先简单介绍一下栈帧结构:
IA32程序用程序栈来支持过程调用。机器用栈来传递过程参数、存储返回信息、保存寄存器用于以后恢复,以及本地存储。为单个过程分配的那部分叫做栈帧。
栈是向下生长的,从内存高地址向低地址路径延伸。栈有栈顶和栈底,栈顶地址比栈底低。
两个寄存器:
ebp—栈指针(基址指针)ebp指向栈底
esp—帧指针 始终指向栈顶
下面对一个简单c程序的函数调用做出分析:
#include <stdio.h>
#include <windows.h>
int fun(int x,int y)
{
int c = 0xcccccccc;
return c;
}
int main()
{
int a = 0xaaaaaaaa;
int b = 0xbbbbbbbb;
int ret = fun(a,b);
printf("you should run here\n");
system("pause");
return 0;
}
1)首先将main函数的ebp入栈。
2)然后将main函数的esp的值赋给ebp,即就是让ebp指向esp指向的空间,让ebp做为fun函数的栈底
3)然后将esp的值减去某个值,为fun函数开辟新的栈空间。
4)fun函数调用结束后,将esp指向ebp的地址,使当前栈帧的ebp恢复为main函数的栈顶。
5)然后从main函数的栈顶弹出main函数的ebp,使ebp恢复为调用fun函数之前main函数的栈底,接着pop出esp的内容–保存的call指令的下一条指令的地址,然后 esp指向指向这个地址。这时esp和ebp都恢复为调用fun函数之前的位置。
对main函数反汇编语言的分析