zoukankan      html  css  js  c++  java
  • C语言中函数执行过程中堆栈的变化

    一个最简易的C函数:执行一个加法

    int add(int x, int y) {
        return x + y;
    }
    
    void main() {
        
        __asm {
            // 下断点
            mov eax, eax;
        }
    
        add(1, 2);
    
        return;
    }

    VS2019中,创建项目。F5执行,右键到反汇编窗口。

    这是main()的对应汇编代码:  

      

     此时的堆栈信息如图:

      

    1 .F10(F11)逐步执行了PUSH 1,PUSH 2(函数执行前传入参数)后,ESP的值减少了2*4=8个字节

    对应堆栈信息如下:

      

    寄存器内容:

      

      可以看到ESP由原来的A88变成了A80,正好减少了8个字节。

     2.F11单步进入函数执行,这里需要注意的是VS执行函数前会先通过JMP指令跳到函数对应的地址,如图:

      

     此时继续F11执行即可进入函数内查看分步信息。

    3.这是add函数执行前的堆栈及寄存器信息:

      

       

    4.函数的执行使用了EBP寻址的方式保证了函数执行前后的堆栈平衡:

    EBP寻址以前也有记录,这里介绍add函数对应汇编指令的含义:

      

    (1)把EBP放入堆栈,同时让栈顶栈底指向同一处
    PUSH EBP
    MOV EBP,ESP

    此时ESP与EBP的状态如图:

      

    (2)开辟当前函数用到的内存,开辟了C0个这么大的内存:
    SUB ESP,0C0h

    C0/4=30,即开辟了30个4字节的内存(30格——3*16=48格格<10进制>),此时的堆栈信息如图:

      

    一格为4字节,sub esp,c0就是开辟了c0个字节的内存,即48格。

    且此时的ESP减少了C0,变成了009EF9B8,而EBP保存了原来的ESP的值。

    (3) 因为函数中可能用到寄存器,但是这个寄存器的内容,在当前函数执行结束以后,后面的程序可能用到,所以需要先将用到的寄存器的内容先push入栈保存起来:
    PUSH EBX
    PUSH ESI
    PUSH EDI

     对应堆栈信息:

      

    (4)向缓冲区(函数开辟的那块内存)循环填入CC程序断点,防止缓冲区溢出.
    LEA EDI,[EBP-0C0h]
    MOV ECX,030h
    MOV EAX,0CCCCCCCCh
    REP SOTS DWORD PTR ES:[EDI]

    MOV ECX,030h

    MOV EAX,0CCCCCCCCh

    REP SOTS DWORD PTR ES:[EDI]

      这三行指令的作用是循环执行把EAX的值放到EDI的位置,循环次数为ECX内保存的值(30h<48>次),正好是当前函数开辟的内存大小。

      执行结束后堆栈信息如下:

      

    且这几行指令执行结束后ESP与EBP的值并没有改变。只是把缓冲区的内容全部填充成了CCCCCCCC断点。以便在缓冲区溢出时及时停止

    (5) 函数执行1+2:把传入的参数x,y相加并保存到eax中
    mov         eax,dword ptr [x]
    add         eax,dword ptr [y]

     此时EAX:

      

    (6)接下来就是恢复堆栈:

    ①还原EDI,ESI,EBX

    POP EDI
    POP ESI
    POP EBX

     ②还原ESP

    ADD ESP,0C0h

    此时堆栈应该ESP=EBP=009EFA78

      

    ③还原EBP:把堆栈中存在栈顶的EBP的值POP到EBP中

    POP EBP

     堆栈信息如图:

      

    ④return:表示add函数执行结束,这里的堆栈已经回到了进入add()函数之前的状态。

    RET

     堆栈如图:

      

     (6)因为还有PUSH两个参数造成的两段已经使用过的内存A84和A88,所以在main()函数中还要进一步恢复:
    ADD ESP,8

     此时的堆栈如图:

      

    这样:ESP和EBP就回到了这个add函数执行之前的样子

  • 相关阅读:
    PPP协议 PAP认证
    交换机广播风暴,STP生成树协议,端口聚合
    传统远程注入线程,加载DLL
    EXE和DLL调用关系,DLL制作,钩子
    window bat批处理 实用脚本
    python利用scapy嗅探流量
    关于AWD线下攻防的经验
    APP 仿微信登录
    价值1500左右的毕业设计都开源啦
    EOS2.0环境搭建-centos7
  • 原文地址:https://www.cnblogs.com/codexlx/p/13333831.html
Copyright © 2011-2022 走看看