栈帧

Posted _NiuLi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了栈帧相关的知识,希望对你有一定的参考价值。

C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。

首先,栈是从高地址向低地址延伸的。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。

先来看一个代码

#include <stdio.h>
void fun()

    int tmp = 10;
    int*p = (int*)(*(&tmp + 1));
    *(p - 1) = 20;

int main()

    int a = 0;
    fun();
    printf("a = %d\\n", a);
    return 0;

这个代码输出的a的值时多少呢?  答案是20。


调用fun()函数后居然把a的值改掉了,从上面的代码可以看到并没有给fun()函数传a的地址,那么fun()函数为什么会把a的值改掉呢?  回答这个问题之前我们需要了解C语言函数的调用过程。


为了更好的观察到上述函数的调用过程,我们在VC 6.0环境下查看一下它的汇编代码。


在这之前首先要知道:

  寄存器ebp称为“基址指针”,在未受改变之前始终指向栈底,用途是:在堆栈中寻址。

  寄存器esp称为“栈指针”,会随着数据的入栈出栈移动,也就是说始终指向栈 顶。



函数调用过程如下图所示:

 图中有部分esp移动的过程没有画出,但最终不管如何入栈出栈esp会在销毁空间后指向创建空间前esp最后指向的位置

          从上面的汇编代码,我们可以看到fun()函数是通过找到变量a所在的栈的栈底地址,进而找到a的地

址,将a的内容改掉,这就解释了为什么没有给fun()传a的地址,却可以改变a的值。


总结:

        函数在调用另一个函数之前会保存两个信息(1)函数调用完返回之后下一条指令的地址

                                                                                          (2)该函数的栈底的地址





最后分享一个使用ebp修改程序执行顺序的代码,并且最后esp回到原处,貌似什么都没发生的样子。


但是却在屏幕上多输出了一个funtest

#include <stdio.h> 
void*p =NULL; 
void*q =NULL; 
void funtest()

    int tmp =0;
    int tmp2 =1;
    printf("funtest\\n");
    *(int*)(&tmp+2) =p; 

void swap(int *pa, int *pb) 

    int tmp=0;
    p= *(&tmp+2);
    q= &tmp+2;
    *(&tmp+2) = &funtest;
    tmp = *pa;
    *pa = *pb;
    *pb = tmp;

int main() 

    int a =10;
    int b =20; 
    swap(&a,&b); 
    printf("main\\n");
    _asm
        sub esp,4
         
    return 0;





本文出自 “牛丽” 博客,请务必保留此出处http://15129279495.blog.51cto.com/10845420/1735749

以上是关于栈帧的主要内容,如果未能解决你的问题,请参考以下文章

堆栈溢出

用CE找到基址 但基址是9位的 为啥在易语言里面查询的数据不对``

使用Ida加载DLL时能指定加载到的基址吗

游戏升级64位基址找不到

学习逆向知识之用于游戏外挂的实现.第三讲,通过游戏外挂.分析红色警戒金钱基址.以及确定基址小技巧.

操作系统用户级线程(协程)执行原理(程序计数器PC,寄存器EBPESP,线程控制块TCB的变化)