C++反汇编第三讲,反汇编中识别虚表指针,以及指向的虚函数地址
C++反汇编第三讲,反汇编中识别虚表指针,以及指向的虚函数地址
讲解之前,了解下什么是虚函数,什么是虚表指针,了解下语法,(也算复习了)
开发知识为了不码字了,找了一篇介绍比较好的,这里我扣过来了,当然也可以看原博客链接: http://blog.csdn.net/hackbuteer1/article/details/7558868
一丶虚函数讲解(复习开发,熟悉内存模型)
1.复习开发知识
首先:强调一个概念
定义一个函数为虚函数,不代表函数为不被实现的函数。
定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
定义一个函数为纯虚函数,才代表函数没有被实现。
定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
1、简介
假设我们有下面的类层次:
class A
{
public: virtual void foo() { cout<<"A::foo() is called"<<endl; }
};
class B:public A
{
public: void foo() { cout<<"B::foo() is called"<<endl; }
};
int main(void)
{ A *a = new B(); a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的! return 0;
}
这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。
虚函数只能借助于指针或者引用来达到多态的效果。
如果看明白上面的开发知识,则我们可以从内存角度看一下虚函数是怎么样存在的.
2.从内存角度看虚函数
首先我们学习C++的时候,自学或者老师教学的时候,都有谈过一个虚表指针的概念.
那我们要知道什么是虚表指针.
2.1
不带虚表指针的高级代码:
class MyTest { public:MyTest();~MyTest();void ShowHelloWorld();int m_Number; };MyTest::MyTest() {printf("MyTest::MyTest()\r\n"); }MyTest::~MyTest() {printf("MyTest::~MyTest()\r\n"); }void MyTest::ShowHelloWorld() {printf("Hello World!\n"); }//类声明在上int main(int argc, char* argv[]) {MyTest obj; //构造obj对象obj.ShowHelloWorld();//调用成员函数obj.m_Number = 1; //成员变量赋值return 0; }
首先看上图高级代码,为什么我们说它没有虚表指针.我们调试查看.
首先经过我们调试
1.obj在监视窗口中只有一个成员变量,且初始化为CCCCC (Debug下)
2.看对象的所在的地址中,发现只申请了4个字节空间,用来存放成员变量.
2.2带虚表指针的高级代码
高级代码还是其高级代码,唯一不同的则是在类中给成员函数加了一个关键字, virtual,让此成员函数变为一个虚函数.
内存模型:
我们发现加了之后会额外多出4个字节空间,而且监视窗口中加了一项虚表指针变量.
构造一下继续观看内存模型.
构造之后发现已经初始化了虚表指针,那么我们进去这个地址后查看有什么内容.
其内容是一个函数指针表,里面存放了虚函数的地址.不相信的话我们打开反汇编窗口,跟进去则可以看到.
总结:
1.没有虚表指针
1.1没有虚函数的情况下没有虚表指针
2.有虚表指针
2.1虚表指针的产生是看你有没有 virtual这个关键字
2.2虚表指针存储的是虚表的首地址,虚表可以看做是一个数组
2.3虚表中存储的是虚函数的地址.
二丶熟悉反汇编中虚表指针,以及还原
既然上面我们熟悉了内存模型,也熟悉了虚函数的原理,那么我们从反汇编的角度下看一下.
例子是我们加了虚函数的例子
Debug下的反汇编
在我们构造的时候,会填写虚表指针,然后核心代码就在上面
1.将对象存入一个局部变量保存
2.局部变量中转给eax
3.对eax取内容填写虚表地址.
总结就是一句话: 取出对象的首4个字节,填写虚表.
那么现在好办了,既然找到了虚表,则可以找到构造,析构,以及虚表中存储的所有虚函数了.
PS: 此图和上图的反汇编一样,只不过高版本的图表没法看,所以用低版本,低版本可以打开.
对其位置下一个引用图表,谁引用了我,则可以看到调用它的所有构造以及析构了,
1.构造的时候会填写虚表
2.析构的时候会填写虚表
图表:
可以看出分别有个构造和析构.那个是构造那个是析构,我们需要跟过去看一下.
根据以前所讲的认识构造和析构的方法,可以很简单的判别出来.
识别虚函数
既然我们找到了虚表指针,则可以双击过去,可以找到虚函数了.
有一个虚函数,确实只有一个,我们跳转过去看看是不是我们定义的
Debug下有跳转表
里面的跳转则是我们的虚函数
总结:
1.识别虚表指针可以在构造中或者析构中查看
2.虚表指针双击过去则可以看到所有的虚函数的地址
3.对虚表指针来个引用,(谁引用我)可以看到所有的构造和析构
三丶识别虚函数的调用
熟悉了虚表指针, 通过虚表指针找构造,析构,以及虚表指针指向的虚表找虚函数,那么我们看一下普通成员函数调用和虚函数调用有什么区别.
PS:类声明不截图,其普通成员函数不加关键字 virtual,其虚函数加virtual
高级代码:
int main(int argc, char* argv[]) {MyTest test;MyTest &obj = test; //可以虚调用obj.print(); //普通成员函数obj.ShowHelloWorld(); //虚函数调用return 0; }
Debug下的反汇编观察.
认真观察可以看出
1.普通成员函数调用,直接Call
2.虚函数调用
2.1 首先获得虚表指针
2.2 间接调用虚表指针指向的虚表的内容(虚成员函数地址)
总结:
识别调用普通成员函数和虚函数的特征则是
1.普通成员函数直接调用Call
2.虚函数会通过虚表指针指向的虚表来间接调用.
转载于:https://www.cnblogs.com/iBinary/p/8001749.html
C++反汇编第三讲,反汇编中识别虚表指针,以及指向的虚函数地址相关推荐
- C++虚表地址和虚函数地址
C++虚表地址和虚函数地址 虚函数是c++实现多态性的一个重要知识点,本文主要解析虚函数在内存中的地址,以及与虚表地址的关系. 声明一个类,包含两个虚函数,一个普通成员函数和一个类成员. 调试程序,查 ...
- 【C 语言】指针间接赋值 ( 直接修改 和 间接修改 指针变量 的值 | 在函数中 间接修改 指针变量 的值 | 在函数中 间接修改 外部变量 的原理 )
文章目录 一.直接修改 和 间接修改 指针变量 的值 二.在函数中 间接修改 指针变量 的值 三.在函数中 间接修改 外部变量 的原理 一.直接修改 和 间接修改 指针变量 的值 直接修改 指针变量 ...
- C++函数中那些不可以被声明为虚函数的函数
常见的不不能声明为虚函数的有:普通函数(非成员函数):静态成员函数:内联成员函数:构造函数:友元函数. 1.为什么C++不支持普通函数为虚函数? 普通函数(非成员函数)只能被overload,不能被o ...
- C++工作笔记- C++中的动态类型与动态绑定、虚函数、运行时多态的实现
动态类型与静态类型 静态类型 是指不需要考虑表达式的执行期语义,仅分析程序文本而决定的表达式类型.静态类型仅依赖于包含表达式的程序文本的形式,而在程序运行时不会改变.通俗的讲,就是上下文无关,在编译时 ...
- 一文读懂C#中的抽象类、抽象方法、virtual虚函数、override重写函数及父类子类构造函数和析构函数的执行顺序
// 父类 class People {public People(){Console.WriteLine("执行People构造函数!");}public virtual voi ...
- c#中的DefWndProc是Control类的虚函数
protected override void DefWndProc(ref Message m) protected override void DefWndProc(ref Message m)是 ...
- C++中虚函数、虚指针和虚表详解
关于虚函数的背景知识 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数. 存在虚函数的类都有一个一维的虚函数表叫做虚表.每一个类的对象都有一个指向虚表开始的虚指针.虚表是和类对应的 ...
- 你了解C++中的虚表吗
虚表 一.什么是虚表 二.虚表是干什么的 一.什么是虚表 在面试中,面试官会问到一个问题,影响一个类大小的因素有哪些? 这是我们就需要知道,影响一个类大小的因素首先就有成员变量,以及继承,以及最重要的 ...
- C++虚函数表,虚表指针,内存分布
虚函数表和内存分布那一块转载自:https://blog.twofei.com/496/ 虚函数效率转载自:https://www.cnblogs.com/rollenholt/articles/20 ...
最新文章
- 数据分析之CE找数据大法
- 少儿不宜!这个开源项目能自动画出各种尺寸的...
- python3 推荐使用super调用base类方法
- django ContentType使用方法
- 实验六 Linux进程编程,Linux系统编程实验六:进程间通信
- why I cannot get any search result from P8F
- Sigmoid函数与Softmax函数的区别与联系
- 华为鸿蒙系统使用视频,原生鸿蒙系统,华为WATCH 3上手视频曝光
- Linux内核写入s3c2440,Linux空板的系统写入
- 卷积、卷积矩阵(Convolution matrix)与核(Kernel)
- Ubuntu环境下导入tensorflow弹出FutureWarning: Passing (type, 1)的解决办法
- SPSS基本数据处理(二)
- 基于python的三维射线追踪库-ttcrpy详解(3)
- 【H3C模拟器】VLAN单臂路由通信:用路由器实现和三层交换机实现
- NLP中的全局注意力机制(Global Attention)
- SEM竞价推广关键词托词方法与词性划分
- 步进电机的计算机控制系统设计,基于计算机并口的步进电机控制系统设计
- 计算机大类和三不限哪个好考,上岸经验 !公考千万别报“三不限”职位!
- rdkit 力场优化UFFOptimizeMolecule、MMFFOptimizeMolecule;chem3D 3D分子生成;获取分子坐标对象
- http协议常见错误状态码(400,404,500等).
热门文章
- php $interval,如何在PHP中使用setInterval?
- Java泛型详解,通俗易懂只需5分钟
- 【译】Google's AutoML: Cutting Through the Hype
- 【译】Using Machine Learning to Understand the Ethereum Blockchain
- Android Zygote分析
- Truffle合约交互 - WEB端对以太坊数据的读写
- 【问链-EOS公开课】第七课 EOS 宪法草案与 BP 协议
- opengl用什么软件写_汇才论文工具分享:写科研论文的都在用这些截图软件
- JZOJ 3815. 【NOIP2014模拟9.7】克卜勒
- php mysql随机记录,php – 从MySQL中选择可变数量的随机记录