首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

实例分析C程序运行时的内存结构

EBP顶初始值为0018FF84h,ESP初始为0018FF48h ESPEBP中的作用 在每个函数最开始的地方有两条语句 push ebp mov  ebp,esp 在函数返回前也有两条语句...mov esp,ebp pop ebp 每运行一个函数就新开一段空间,所谓的开空间就是移动ebp底,在移动ebp之前,通过push ebp保存上一级函数的底,然后用ebp指向现在函数顶,即为当前函数开辟了...;接着给局部变量进行地址分配以及保存现场等,esp不断向低地址移动,当函数调用结束时,esp指回当前函数的顶(mov esp,ebp),然后上一级函数的顶地址出保存在ebp中(pop ebp)。.../ ebp保存顶0,ebp=esp=0018FF44h 00401023   sub         esp,48h                    // esp -= 48h开辟了一段空间,...// ebp恢复为0018FF44h 004010C1   ret                                    // 返回,等待执行函数调用的下一条指令 在调用fun函数之前,

1.1K10

恶意样本对抗回溯检测机制的套路浅析

push ebp ; 先将属于调用函数的 EBP 值压,执行后 ESP 指向地址存储该 EBP 的值 mov ebp, esp ; 将 ESP 的值赋给 EBP 寄存器,执行后 EBP 指向地址存储属于调用函数的...EBP 始终保持不变 mov esp, ebp ; 将 EBP 的值赋给 ESP 寄存器,执行后 ESP 指向地址存储属于调用函数的 EBP 的值 pop ebp ; 弹出保存在中的调用函数的...根据上面帧结构和 CALL 指令的操作可知,在将属于调用函数的 EBP 的值压之前,ESP 指向的地址存储的是由 CALL 指令压调用函数中调用位置的下一条指令的地址(原 EIP)。...下面的代码片段实现了分配新的缓冲区,并拷贝从 ESP 指针指向位置到 调用函数的 EBP中存储位置加上调用函数的返回地址的存储位置这个范围的片段,到新分配的缓冲区中最高位置区域,为低内存预留了...delta = p_ebp - p_esp; // 获取调用者的 EBP中的位置 if (p_esp > stacklimit && p_esp < stackbase

80920
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    通过一篇文章让你了解什么是函数

    当一个函数被调用时,它的局部变量和函数参数等信息会被压入中。ESP寄存器指向顶的地址,即最后被压入的数据所在的内存地址。使用ESP寄存器,可以轻松地在上分配和释放内存。...总之,ESP寄存器在x86架构中用于指向当前顶的地址,可以方便地进行函数调用操作。...每一次函数调用,都要为本次函数调用开辟空间,就是函数帧的空间。 这块空间的维护是使用了2个寄存器: espebpebp 记录的是底的地址, esp 记录的是顶的地址。...esp,0E4h //sub会让esp中的地址减去一个16进制数字0xe4,产生新的esp,此时的esp是main函数帧的esp,此时结合上一条指令的ebp和当前的espebp和...将main函数的 ebp 计算新的 ebpesp 将 ebx , esi , edi 寄存器的值保存 计算求和,在计算求和的时候,我们是通过 ebp 中的地址进行偏移访问到了函数调用前压进去的参数

    26710

    5.5 汇编语言:函数调用约定

    顶指针esp小于底指针ebp时,就形成了帧,帧中可以寻址的数据有局部变量,函数返回地址,函数参数等。...不同的两次函数调用,所形成的帧也不相同,当由一个函数进入另一个函数时,就会针对调用的函数开辟出其所需的空间,形成此函数的独有帧,而当调用结束时,则清除掉它所使用的空间,关闭帧,该过程通俗的讲叫做平衡...; 保存底指针ebp mov ebp,esp ; 调整当前底指针到顶 sub esp,0e4h...这种调用方式规定函数调用者在将参数压入中后,再将控制权转移到被调用函数,被调用函数通过顶指针ESP来访问这些参数。函数返回时,由调用者程序负责将堆栈平衡清除。...该调用方式在函数内不进行任何平衡参数操作,而是在退出函数后对esp执行加4操作,从而实现平衡。

    31920

    指针&& 帧指针详解

    所以任何函数调用进来的第一件事都是保护调用者的帧指针,以使得返回时可以恢复调用者的帧指针,即pushl %ebp movl %esp %ebp有了上面这两个命令,函数就可返回了,返回时只要leave...在函数执行过程中,指针esp会随着数据的入和出而移动,因此函数中对大部分数据的访问都基于帧指针%ebp进行。?对于函数A调用函数B的情况,传递给B的参数包含在A的帧中。...(执行完此指令后,指针esp会向下移动,指向保存原ebp的空间的地方)4 movl %esp,%ebp (把数据(原ebp的值)压入后,指针esp会向下移动4个字节指向放原ebp的值的空间,执行此句指令的意义就...是把esp指向的地址赋值给%ebp,%ebp作为新:_swap底指针或者说是新的帧指针ebp使用)5 subl $4,%esp # 为局部变量c在内分配空间。...)的地址传送给寄存器%eax,此时 帧指针esp指向了-12%ebp处)25 pushl %eax # 作为调用的参数并压入中。

    8.7K31

    C语言:底层剖析——函数帧的创建和销毁

    2、这块空间的维护是使用了两个寄存器:espebp(也可以理解成两个指针),ebp记录的是底的地址,esp记录的是顶的地址,而这两个地址就是用来维护函数帧的。...2.mov    ebpesp  move指令会把esp的值存放带ebp中,相当于产生了main函数的ebp,这个值就是invoke_main函数帧的esp。...相当于回收了Add函数的帧空间 pop         ebp       弹出顶的值存放到ebp顶此时的值恰好就是main函数的ebpesp+4,此时恢复了main函数的帧维护,esp...因为esp顶寄存器)和ebp底寄存器)用来维护函数的帧,他会根据调用函数的不同去向不同的位置,由于区的使用习惯时从高地址指向低地址,那么当Add函数执行完后想要回到main函数,此时Add的...ebp恰好就可以是main函数的esp,但是main函数的ebp此时已经不知道在哪里了,为了避免这种情况,创建Add函数帧的时候,espebp在变化维护的帧空间之前,会记录原来空间的底地址也就是

    38510

    【内功修炼】深入理解函数帧的创建和销毁

    我们的程序中正在调用哪个函数,ebpesp维护的就是哪个函数的帧。...是的,ebpesp新维护的这块空间其实就是给main函数开辟的空间,也就是main函数的帧 所以,我们上面也提到:我们的程序中正在调用哪个函数,ebpesp维护的就是哪个函数的帧...总结一下: sub会让esp中的地址减去一个16进制数字0xe4,产生新的esp,此时新的esp就是main函数帧的esp,此时结合上一条指令的ebp和当前的espebpesp之间维护了一块新的空间...那我们还是来带大家简单分析一下: 首先呢又是 push ebp 把此时的ebp的值压 然后mov ebp,esp 之前ebp是在维护main函数的帧 那现在mov ebp,espesp...那就变成这样了 我们发现此时ebpesp又重新维护起了main函数的帧,这当然没问题,因为此时Add函数已经调用结束,就要回到main函数了。

    26511

    函数调用过程(帧)

    开发环境 Ubuntu 14.04(32bits) GCC 编辑器 Cmd Markdown 画图工具 Processon 1,函数调用过程 今天先介绍下基本的函数调用过程,即帧。...1.1帧 每个函数调用都对应一个帧。每个帧由ESPEBP寄存器来确定。每个函数执行时,其局部变量都是在自己对应的帧内分配内存。...//将ebp,即old ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp //ebp=esp .cfi_def_cfa_register...5 andl $-16, %esp //esp=esp&0xFFFFFFF0,即保证esp的最低4位为0 subl $32, %esp //向低地址生长,esp-=32 movl $10...//将变量i的值压 call test //调用test函数,其中将下条指令(即movl %eax, 28(%esp))\ 的地址压,即ret addr,然后转到test函数执行,即eip=test

    85120

    【C语言】函数——帧的创建和销毁

    每一次函数调用,都要为本次函数调用开辟空间,就是函数帧的空间。 2.这块空间的维护是使用了2个寄存器: espebpebp 记录的是底的地址, esp 记录的是顶的地址。...mov ecx,dword ptr [ebp-8] //传递a,将ebp-8处放的3放在ecx寄存器中 00BE1857 push ecx //将ecx的值压esp-4 //跳转调用函数 00BE1858...ebp-8处放的3放在ecx寄存器中 00BE1857 push ecx //将ecx的值压esp-4 //跳转调用函数 00BE1858 call 00BE10B4 00BE185D add esp...esp,8 00BE1860 mov dword ptr [ebp-20h],eax call 指令是要执行函数调用逻辑的,在执行call指令之前先会把call指令的下一条指令的地址进行压 操作,这个操作是为了解决当函数调用结束后要回到...将main函数的 ebp 计算新的 ebpesp 将 ebx , esi , edi 寄存器的值保存 计算求和,在计算求和的时候,我们是通过 ebp 中的地址进行偏移访问到了函数调用前压进去的

    59410

    5.5 汇编语言:函数调用约定

    结构在内存中占用一段连续存储空间,通过espebp这两个指针寄存器来保存当前起始地址与结束地址,每4个字节保存一个数据。...当顶指针esp小于底指针ebp时,就形成了帧,帧中可以寻址的数据有局部变量,函数返回地址,函数参数等。...不同的两次函数调用,所形成的帧也不相同,当由一个函数进入另一个函数时,就会针对调用的函数开辟出其所需的空间,形成此函数的独有帧,而当调用结束时,则清除掉它所使用的空间,关闭帧,该过程通俗的讲叫做平衡...这种调用方式规定函数调用者在将参数压入中后,再将控制权转移到被调用函数,被调用函数通过顶指针ESP来访问这些参数。函数返回时,由调用者程序负责将堆栈平衡清除。...该调用方式在函数内不进行任何平衡参数操作,而是在退出函数后对esp执行加4操作,从而实现平衡。

    26120

    从汇编角度来理解linux下多层函数调用堆栈运行状态

    esp寄存器总是指向顶,在x86平台上这个是从高地址向低地址增长的,我们知道每次调用一个函数都要分配一个帧来保存参数和局部变量,现在我们详细分析这些数据在空间的布局,根据gdb的输出结果图示如下...call   80483f2  要调用函数foo先要把参数准备好,第二个参数保存在esp+4指向的内存位置,第一个参数保存在esp指向的内存位置,可见参数是从右向左依次压的。...在每个函数的帧中,ebp指向底,而esp指向顶,在函数执行过程中esp随着压和出操作随时变化,而ebp是不动的,函数的参数和局部变量都是通过ebp的值加上一个偏移量来访问,例如foo函数的参数...现在esp所指向的顶保存着foo函数帧的ebp,把这个值恢复给ebp,同时esp增加4,esp的值变成0xbffff68c。 最后是ret指令,它是call指令的逆操作: 1....注意函数调用和返回过程中的这些规则: 1. 参数压传递,并且是从右向左依次压。 2. ebp总是指向当前帧的底。 3. 返回值通过eax寄存器传递。

    94620

    图解函数调用过程

    在系统中程序执行的时候都是从高地址往低地址增长的 函数参数压,一般从右向左压(比如__cdecl函数调用约定) EIP寄存器存储当前执行指令的内存位置 EBP寄存器表明当前帧的ESP寄存器表明当前帧的顶...push ebp 步骤2.2 修改底,将当前ESP设置为EBP,切换到当前函数FunAdd的帧。...mov ebp,esp 步骤2.3 将ESP减去8,即增长8个字节(记住是从高地址往低地址增长的)这个操作就等于在上申请了8个字节的空间,为什么是8个字节呢?...mov esp,ebp pop ebp 步骤2.9 此时的ESP指向的值正是在第一步中保存的Return Address,即FunAdd调用后的下一条指令。...add esp,8 mov dword ptr [ebp-0Ch],eax 首先调用add esp, 8即将顶去除八个字节,而这8个字节正是用来存储FunAdd入参数的。

    2.3K71

    汇编角度看函数堆栈调用

    esp:专门用作堆栈指针,被形象的称为顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,esp就越来越小。在32位平台上,esp每次减少4个字节。 ebp:堆栈的底指针。...开始分析函数帧开辟的过程: 00401060 push ebp 00401061 mov ebp,esp 00401063 sub esp,4Ch...2.0040104E mov esp,ebp使得被调用函数帧回退。此时帧空间的内容还存在。 3.pop ebp 两个动作,出,并将出的值赋给ebp。...esp,8 相当于esp = esp + 8,是主函数压实参的帧回退。...答: (1)形参的内存空间的开辟和清理是由调用方执行的。 (2)主函数调用函数后执行执行调用之后的代码,是因为调用方在进行调用的过程中,将下一行指令的地址压

    65220

    C语言函数的帧详解

    3.1 main函数帧创建 ​ 根据VS2013编译器调试,调用堆栈,不难发现main函数的调用链条如下: 很显然main函数在被调用时,创建了帧。...在调试过程中将转到反汇编,便能直观的看到main函数帧创建的过程。首先需明确的是,函数帧由寄存器esp,ebp维护。...,如图所示esp指向ebpebp成功压入中。...2.esp值传递给ebp。 3.esp减去0E4h:由于先使用高地址后使用低地址,减去一个值意味着esp指针向低地址移动了0E4h个地址,此处便开辟了main函数的帧。...,ebx,随后将ebp赋给esp并弹出ebp,最后执行ret指令返回到调用Add函数的call指令的下一地址,在执行ret指令时实际已弹出After call,以执行指令 add esp,8,此时esp

    2.1K20

    你一定要搞明白的C函数调用方式与原理

    在函数调用前,main正在用ESPEBP寄存器指示它自己的帧。 首先,main把EAX,ECX和EDX压。这是一个可选的步骤,只在这三个寄存器内容需要保留的时候执行此步骤。...首先foo必须建立它自己的帧。EBP寄存器现在正指向main的帧中的某个位置,这个值必须被保留,因此,EBP。然后ESP的内容赋值给了EBP。...如此一来,几乎所有的c函数都由如下两个指令开始: push ebp mov ebp, esp 此时的入图3所示。...这其中也许有进、出的动作,指针ESP也会上下移动,但EBP是保持不变的。这意味着我们可以一直用[EBP+8]找到第一个参数,而不管在函数中有多少进出的动作。...开始进入Main函数 esp=0x12FF84 ebp=0x12FFC0 完成椭圆形框起来的部分: 00401070 push ebp ebp的值入,保存现场(调用现场,从test

    3.3K30

    C语言——F函数的帧的创建和销毁

    相关汇编命令 mov:数据转移指令 push:数据入,同时esp顶寄存器也要发生改变 pop:数据弹出至指定位置,同时esp顶寄存器也要发生改变 sub:减法命令 add:加法命令 call:函数调用...2、这块空间的维护是使用了2个寄存器: espebpebp 记录的是底的地址, esp 记录的是顶的地址。 3、函数帧的创建和销毁过程,在不同的编译器上实现的方法大同小异。...mov ecx,dword ptr [ebp-8] //传递a,将ebp-8处放的10放在ecx寄存器中 00BE1857 push ecx //将ecx的值压esp-4 //跳转调用函数...//在顶弹出一个值,存放到ebx中,esp+4 00BE1782 mov esp,ebp //再将Add函数的ebp的值赋值给esp,相当于回收了Add函数的帧空间 00BE1784 pop ebp...//弹出顶的值存放到ebp顶此时的值恰好就是main函数的ebpesp+4,此时恢复了main函数的帧维护,esp指向main函数帧的顶,ebp指向了main函数帧的底。

    10810

    反汇编窥探函数调用过程

    哦,首先要看一下此时的空间状况,此时的空间由EBPESP两个寄存器来决定,EBP底的内存地址,ESP顶的内存地址。看一下吧。...call指令还有一个隐含的操作,就是把call指令下面的一条指令的内存地址压入中,方便函数调用结束后找到下一条指令的位置。即将00D71844压入中。然后顶指针esp往上走。...[3u2t0igzfl.png] 然后执行2号指令,mov ebpesp,此时ebp的值和esp的值相同,底指针和顶指针处于同一水平线上。...此时ebpesp又回到了同一水平线上。 [hs28ee5mgp.png] 然后执行13号指令,pop ebp,就是把调用test函数之前的起始内存地址弹出来,此时ebp的值为010ff82c。...并且,底指针,顶指针位置回到函数调用前的状态,调用过程结束。

    99320
    领券