C++逆向分析----多重继承和菱形继承
多重继承
多重继承是指C++类同时继承两个类或两个以上的类。
class Test
{
public:
int num1;
Test()
{
num1 = 1;
}
virtual void Proc1();
virtual void Proc2();
};
class Test1
{
public:
int num2;
Test1()
{
num2 = 2;
}
virtual void Proc3();
virtual void Proc4();
};
class Test2:public Test, public Test1
{
public:
int num3;
Test2()
{
num3 = 3;
}
virtual void Proc2();
virtual void Proc4();
virtual void Proc5();
};
Test2 test;
对于多重继承而言,对象会有多个虚表指针。首先调用第一个继承的类Test的构造函数(传递的this指针就是对象首地址),接着会调用第二个继承类Test1的构造函数(传递的this指针是对应类数据在对象中的地址,将对象首地址偏移指定地址后传入。这样就可以避免访问到Test类的成员变量)。接着回到Test2的构造函数中初始化两个虚表指针(也就是说其含有两个虚表)。
我们看一下调用完Test2的构造函数后对象内存处的值,发现会有两个虚表指针。分别在连个父类的前4个字节中。
查看两个虚表发现,第一个虚表中存储的是继承第一个类的虚函数地址,如果其虚函数在子类Test2中被覆盖则地址也会被覆盖。第二个虚表中存储的是继承第二个类的虚函数地址,同样其虚函数在子类Test2中被覆盖则地址也会被覆盖。那么如果在Test2类中新增的虚函数其地址存放到哪呢?一般编译器都会将其存在第一个虚表中靠后的地址处。
菱形继承
class Test
{
public:
int num1;
virtual void Proc1();
virtual void Proc2();
virtual void Proc3();
};
class Test1:virtual public Test
{
public:
int num2;
Test1(){
num2 = 0x02;
num1 = 0x01;
};
virtual void Proc1();
virtual void Proc4();
};
class Test2:virtual public Test
{
public:
int num3;
Test2(){
num3 = 0x03;
}
};
class Test3:public Test1, public Test2
{
public:
int num4;
Test3(){
num4 = 0x04;
}
};
上面的示例就是一个典型的菱形继承,且为了保证Test数据成员在Test3类对象中的唯一性,需要Test1继承Test(Test2继承Test)时采用虚继承。
菱形继承内存的布局如下,其有三个虚表指针。父类除了包含虚表指针外还包含一个vt_offset域,此域包含两个字段,第一个字段是本类虚表指针相对于vt_Offset域的偏移,第二个字段是本类的父类(祖父类)的虚表指针相对于vt_offset域的偏移。
注意两个父类虚表指针中包含的是父类中新定义的虚函数,如果其覆盖祖父类中的虚函数其地址应该在祖父类的那个虚表指针中。其中子类也会覆盖父类中的虚函数,那如果其新增虚函数地址应该放在哪呢?编译器一般是将其放在第一个继承的类的虚表指针中,也就是虚表指针1指向的虚表靠后的位置。
调用两个父类或祖父类的构造函数时都会将对象首地址往后偏移到对应的类处的地址后当this指针传递,这样可以在父类或祖父类的构造函数中直接通过偏移访问其自己的类成员。那么现在有个问题在父类的构造函数中访问子类的成员变量应该如何访问呢,祖父类的数据成员在对象的最底部如果单单利用顺序偏移的关系是无法正确访问的,实际其实利用vt_offset域的第二个字段父类对应虚表指针相对于vt_offset的偏移来访问的,因为对于祖父类而言其虚表指针后面跟着的就是自己的成员变量。
参考《C++反汇编与逆向分析技术揭秘》
最新文章
- MongoDB Windows环境安装及配置
- IHttpHandler给图片加水印
- 《BI那点儿事》SSRS图表和仪表——雷达图分析三国超一流谋士、统帅数据(图文并茂)
- ListView 选择多项目返回的之前的那项
- windows“画图”工具用法
- c-指针的指针
- css叠加原则,就近原则
- Chrome 33+ 自建 扩展 实现 custom.css
- MySQL游标的简单实践
- HDU 1024 Max Sum Plus Plus(DP的简单优化)
- 12.vue属性.监听.组件
- python的set处理二维数组转一维数组
- svn上传和下载项目
- iOS-项目开发1-Block
- python中super与成员属性
- Python3 Scrapy 安装方法
- [Oracle收费标准]
- Android面试收集录18 Android Context详解
- B - Help Jimmy
- wordpress系列1:安装
热门文章
- ELK(ElasticSearch+Logstash+Kibana)配置中的一些坑基于7.6版本
- 前端 | JS Promise:axios 请求结果后面的 .then() 是什么意思?
- kubernetes删除pod一直处于terminating状态的解决方法
- A. 【例题1】奶牛晒衣服
- 201871030122-牛建疆 实验三 结对项目——《D{0-1}KP 实例数据集算法实验平台》项目报告
- C#字符处理的性能问题
- Java(279-298)【异常、线程】
- Array.prototype.fill 填充值被复用的问题
- CrackMe_002
- ret2dl64