关于栈结构的一些总结

前几天在分析一款软件的时候,发现在分析栈的时候晕圈了,索性今天就总结一波吧:

先看一个demo:

void f1(int a, int b, int c)
{
    int d = a + b + c;


}

int f(int a,int b)
{
    int c = a + b;
    f1(1,2,3);
    return  c;
}

int main()
{

    f(2,3);


    return 0;
}

主函数:

这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这是上面在主函数里面调用函数f之前的情况;
此时上一个ebp还没变;

进入f函数

这里写图片描述
这里写图片描述
这里写图片描述
保存上一个ebp(主函数的ebp);
设立一个新的ebp
这里写图片描述
设立新的esp;
这里写图片描述
safecookie前;
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
safecookie之后;(这里由于原来的demo的图片丢了,这里重新截图的,有随机基址的!只要了解其逻辑即可!)实际上是对局部变量赋值!(注意其方向)

这里写图片描述
调用函数前;

f1函数

这里写图片描述
调用函数时候;
保存上一个ebp;
这里写图片描述
这里写图片描述
设立一个新的ebp,设立新的esp;

这里写图片描述
这里写图片描述
这里写图片描述
上面2幅图,看栈的变化
看栈的变化
这是safecookie
这里写图片描述
这里写图片描述
这里写图片描述
仔细观察这3个图
最后一张图pop ebp恢复了上一个栈帧
即此时ebp里面装的是上一个栈帧的ebp
这里写图片描述
这里写图片描述
执行完retn指令之后
retn 就等于esp + 4,jmp 上一层函数的的下一条指令
其实就是retn = pop eip
retn N操作:先eip=esp,然后esp=esp+4+N
这里写图片描述
这里写图片描述
这里写图片描述
retn 调用 之前
这里写图片描述
retn 调用 之后

总结

能使得esp发生变化的指令:

  • push ——->esp=esp-4
  • pop ———>esp=esp+4
  • call指令(等效于以下指令):
    将call的下一条指令的地址压栈
    jmp 函数地址;
  • ret指令(等效于ret = pop eip):
    1.将当前栈顶中值(一般为返回地址)出栈,”放入”eip中;
    2.返回至上一层函数(其实放入eip中就已经注定这样结局)

  • sub esp, 0xXX

  • add esp,0xXX

猜你喜欢

转载自blog.csdn.net/richard1230/article/details/80058410