栈帧的形成和关闭

  • 当栈顶指针小于栈底指针时就形成了栈帧 (esp < ebp)

    • 需要注意的是,栈的增长方向是地址减小的方向
  • 进入到新函数的时候,就会相应生成栈帧,当结束的时候,就会清除使用的栈空间(栈平衡)
  • Debug版本中,在函数退出的时候,会检查esp是否等于ebp以此检查栈平衡。若不平衡则调用__chkesp() 弹出提示框。
  • 实际进入函数过程
    • 先保存原来的ebp,edi、esi寄存器到栈中
    • 然后调整ebp的位置到esp。也即是调整新函数栈帧
    • 接着通过sub esp,xxh 打开0x40大小的栈空间,是留给局部变量使用的
    • 结束的时候 又会通过 add esp,xxh 释放栈空间
    • 将原本的ebp地址从栈中弹出,恢复调用函数的栈帧

通过使用O2选项,就不会有检查栈平衡的代码,还可能没有保存环境、使用ebp保存当前栈底等一系列操作,代码会变得简洁高效。

各种调用方式的考察

因为函数调用会有不定参数的问题,如果参数是不定参数的时候,被调用函数不知道具体的参数数目,就需要调用他的函数平衡栈。但是正常情况下,被调用函数可以自己平衡栈。

三种调用约定

  • _cdecl: C/C++默认调用方式,调用函数平衡栈,可使用不定参数
  • _stdcall: 被调用函数平衡栈,所以不能使用不定参数
  • _fastcall: 寄存器方式传参,被调用函数平衡栈,不能使用不定参数

所以,可以通过传参方式和平衡栈的方式来判断调用方式

_stdcall

  • 退出函数时会通过 ret x; 的方式平衡栈顶,等价于 esp += x

  • 有时不一定通过ret平衡,也可能通过pop等指令平衡,具体需要看代码怎么使用栈的

_cdecl

  • 在被调用函数中不需要操作,调用函数的call指令下面add esp,x;来平衡栈

  • 复写传播,_cdecl方式的函数在同一作用域多次使用的时候,,最后可以一起平衡栈

_fastcall

  • 使用寄存器传参,但是寄存器智能使用edx和ecx多余的参数依旧需要栈传参

所以,实际传参效率 _fastcall > _cdecl > _stdcall

使用ebp或者esp寻址

在不是O2选项时,会使用ebp寻址局部变量

否则在O2选项中,为了节省寄存器,使用esp寻址

寻址的本质不过是对ebp或者esp做加减法操作,使得地址产生偏移,获取对应的值

因为IDA考虑到方便区分参数和局部变量,所以对于局部变量的寻址使用负数标号

因为调用函数的过程,是先将参数压栈,然后使用call指令,所以参数的偏移应该是正数。

函数调用过程

  • 根据调用方式不同,参数压栈或者寄存器赋值
  • 执行call指令,此时将call的下一条指令压栈
  • 然后执行push ebp保存调用函数的栈底指针
  • mov ebp,esp 则将调整出被调用函数的栈帧,此时ebp == esp,此时参数相对于ebp来说是高地址
  • 一般来说,会通过sub esp,xxh 来分配局部变量的空间
  • 在Debug模式下,会将他们通过rep stos 指令填充cccccccc也即是int 3中断防止这里的东西被执行
  • 退出的时候,根据上面sub esp,xxh的值,给他add esp,xxh回去,就是释放局部变量
  • 根据调用方式,_fastcall 和 _stdcall需要函数中平衡栈
  • pop出调用函数的ebp还原调用函数的栈帧
  • ret指令返回
  • 若是_cdecl 调用,则通过add esp,xxh的方式平衡栈

某次调用函数时的栈结构

函数参数

使用push指令将数据压入栈中,而push实际上是把操作数复制到栈顶,所以此时压入栈的数据和原数据是不同的,相互独立。所以函数中修改参数,不会影响原来的数据。

不定长参数

C/C++将不定长参数的函数定义为:

  • 至少有一个参数
  • 所有不定长的参数类型传入是都是dword类型
  • 需要在某一个参数中说明参数个数或者最后一个参数赋值为结尾标记

只要获得第一个参数的地址,那么只要对这个地址多加法就能获得其他参数。

获取参数类型是为了解释地址中的数据。

printf就是通过第一个参数获取参数总数的,字符串中几个%就是几个参数(%%)除外

函数的返回值

一般来说都是给eax赋值来传递返回值的

而如果是结构体,成员只有两个就使用eax和edx传递返回值。

[C++逆向] 6 函数的工作原理的更多相关文章

  1. eval函数的工作原理

    如果您想详细了解eval和JSON请参考以下链接: eval  :https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Glob ...

  2. C++虚函数的工作原理

    静态绑定与动态绑定 讨论静态绑定与动态绑定,首先需要理解的是绑定,何为绑定?函数调用与函数本身的关联,以及成员访问与变量内存地址间的关系,称为绑定. 理解了绑定后再理解静态与动态. 静态绑定:指在程序 ...

  3. C++中虚函数的作用和虚函数的工作原理

    1 C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函数 ...

  4. 《C++反汇编与逆向分析技术揭秘》——函数的工作原理

    各种调用方式的考察 示例: cdecl方式是调用者清空堆栈: 如果执行的是fastcall: 借助两个寄存器传递参数: 参数1和2借助局部变量来存储: 返回值 如果返回值是结构体: 返回值存放在eax ...

  5. 虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

    #include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout < ...

  6. C++虚函数工作原理

    一.虚函数的工作原理      虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数.典型情况下,这一信息具有一种被称为 vptr(virtual table poi ...

  7. python中的函数、生成器的工作原理

    1.python中函数的工作原理 def foo(): bar() def bar(): pass python的解释器,也就是python.exe(c编写)会用PyEval_EvalFramEx(c ...

  8. 从零入门 Serverless | 一文搞懂函数计算及其工作原理

    作者 | 孔德慧(夏莞) 阿里云函数计算开发工程师 什么是函数计算 大家都了解,Serverless 并不是没有服务器,而是开发者不再需要关心服务器.下图是一个应用从开发到上线的对比图: 在传统 Se ...

  9. day15生成器send方法,递归,匿名函数,max结合匿名工作原理,常用的内置函数

    复习 ''' 1.带参装饰器 - 自定义 | wraps def wrap(info) def outer1(func): from functools import wraps @wraps(fun ...

  10. 20140415 HOG 不同继承方式的访问特性 虚函数工作原理

    1.HOG block重叠的好处 由于行人通常其形状可以视为柔体,人 的边缘位置不固定,而有一些移动,block 重叠后,一个边缘的梯度信息在两个相邻重叠的 block 中都能有所表达,这样即使边缘的 ...

随机推荐

  1. 重新学习一下new Date()

    new Date()你知道多少 很多小伙伴可能都知道, Date是js中的一个内置对象,用于处理日期和时间. 当你调用 new Date() 时,它会创建一个新的日期(Date) 对象. 表示当前本地 ...

  2. Redux和@reduxjs/toolkit的使用

    1. 简介: Redux 是一种用于管理应用程序状态的 JavaScript 库.它是一个可预测的状态容器,可以用于编写 可维护和可扩展的应用程序. @reduxjs/toolkit 是一个官方提供的 ...

  3. javaScript随机图片

    <script type="text/javascript"> //<!CDATA[ var pic = []; pic[0] = "链接"; ...

  4. python3 牛客网:OJ在线编程常见输入输出练习(ACM模式)

    牛客网: 校招笔试真题_C++工程师.golang工程师_牛客网 其他语言输入输出见链接 1.输入两个数,输入数据包括多组. while True: try: a = list(map(int,inp ...

  5. C/C++ 常用开发代码片段

    由于内容较少,所以,不想把它放在我的本地博客中了,暂时保存在这里,代码有一部分来源于网络,比较经典的案例,同样收藏起来. Stack 栈容器 Stack容器适配器中的数据是以LIFO的方式组织的,它是 ...

  6. 月薪10K码农,跳槽到40K架构师,技术学习路线图汇总

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.介绍 Hey there! Roadmap to becoming a web devel ...

  7. webrtc终极版(二)搭建自己的iceserver服务,并用到RTCMultiConnection的demo中

    webrtc终极版(二)搭建自己的iceserver服务,并用到RTCMultiConnection的demo中 目录 webrtc终极版(二)搭建自己的iceserver服务,并用到RTCMulti ...

  8. 如何快速获取AWR中涉及到的表

    最近遇到一个很少见的需求,是关于应用测试方面的. 具体来说,这个应用的测试需求要基于一个固定的时间点数据,而且只能测试一轮,再测试就需要还原到测试前状态. 因为我们使用的存储是分层的(热数据在Flas ...

  9. ASP.NET Core分布式项目实战(详解oauth2授权码流程)--学习笔记

    最近公司产品上线,通宵加班了一个月,一直没有更新,今天开始恢复,每日一更,冲冲冲 任务13:详解oauth2授权码流程 我们即将开发的产品有一个用户 API,一个项目服务 API,每个服务都需要认证授 ...

  10. 【调试】pstore原理和使用方法总结

    什么是pstore pstore最初是用于系统发生oops或panic时,自动保存内核log buffer中的日志.不过在当前内核版本中,其已经支持了更多的功能,如保存console日志.ftrace ...