首页 > 编程语言 >C++逆向分析——继承

C++逆向分析——继承

时间:2023-08-02 18:33:13浏览次数:32  
标签:逆向 struct Person 继承 age C++ int Teacher

继承

struct Person {

int age;


int sex;

};
 
struct Teacher {

int age;


int sex;


int level;


int classId;

};

如上代码中可以看见,Teacher类与Person类都存在着相同的2个成员age和sex,那么这就相当于重复编写了,我们可以通过继承的方式避免这样重复的编写(当前类名称:要继承的类名称):

struct Teacher:Person {

int level;


int classId;

};

创建对象的对应反汇编代码如下,可以清晰的看见与我们正常的内存布局是一样的:

C++逆向分析——继承_内存布局

那么继承是什么?这就很好理解了,继承的本质就是数据复制,子类(派生类)继承(复制)父类(基类)的数据,在这里Person父类(基类),Teacher为子类(派生类);继承可以减少重复代码的编写。

假设,子类中存在一个与父类中相同的成员会如何?

struct Person {

int age;


int sex;

};
 

struct Teacher:Person { // Inherit


int age;


int classId;

};

我们可以创建一个对象来看一下对应的宽度和反汇编代码:

void main() {

 Teacher t;

 t.age = 30;


 t.sex = 1;


 t.classId = 20;

 

 printf("%d", sizeof(t));


 printf("%d", sizeof(t));


return;

}

首先看下数据宽度,我们会发现是16,那也就是说这里不管如何你只要继承了,在编译器中两个成员还是会直接添加过来,Teacher的成员依然是4个「4成员*4数据宽度(int类型) = 16」

C++逆向分析——继承_内存布局_02

再来看下反汇编代码:

C++逆向分析——继承_数据_03

之前我们已经看过了正常的内存布局了,在这里,很明显,少了一个0x10位置的成员,那么按照内存布局应该是这样的:

0x10 → Person.age

0x0C → Person.sex

0x08 → Teacher.age

0x04 → Teacher.classId

而在这里创建对象编译器使用的age成员默认就是当前类Teacher的成员;想要使用父类中的成员可以使用这种方式(对象名.父类名称::成员名称):

void main() {

 Teacher t;

 t.Person::age = 30; // Father


 t.age = 30;


 t.sex = 1;


 t.classId = 20;

 

return;

}

子类与父类成员重名的问题我们可以通过这种方式解决,但是在实际应用中还是尽量避免这种问题比较好。

 

我自己实践下内存布局:

#include <stdio.h>
struct Person {
	int age;
	int sex;
};

struct Teacher :Person { // Inherit
	int age2;
	int classId;
};

 
void main() {
	Teacher t;
	t.age = 30;//ebp-24
	t.age2 = 99;//ebp-16
	t.sex = 1;//ebp-20
	t.classId = 20;//ebp-12

	printf("%d", sizeof(t));
	printf("%d", sizeof(t));
	return;
}

 ODB里看到的:

C++逆向分析——继承_数据_04

vs 2022里反汇编,可以看到父类age的变量地址对应的是[t]这个基址。==》看后面那个图!

C++逆向分析——继承_内存布局_05

 

 

 

我们可以多次继承么,或者说继承仅仅局限于子、父关系么?如下代码,B继承了A,C继承了B,C是否只继承了B的v和n?

struct A {

int x;


int y;

};
 
struct B:A {

int v;


int n;

};
 
struct C:B {

int p;


int o;

};

我们可以来打印一下C的数据宽度:

C++逆向分析——继承_内存布局_06

结果是24,那么就说明C不仅仅继承了B,还继承了A;再换个说法就是,继承的本质是数据的复制,那也就是说当复制完(继承)后才是其本身,B的本身就是4个成员x、y、v、n。==》看这个图就完全明白了!!!

C++逆向分析——继承_内存布局_07

除了这种方式以外,我们想实现同样的效果可以使用多重继承(当前类:继承的类A, 继承的类B):

struct A {

int x;


int y;

};
 
struct B {

int v;


int n;

};
 

struct C:A,B { // Multiple


int p;


int o;

};

但这种方式在很多面向对象语言中是不允许时间的,在C++中是可以使用的,其内存分布也与第一种方式不一样:

C++逆向分析——继承_父类_08

最后:继承的类A和继承的类B的顺序,谁在前,谁就在内存分布中的前面;不推荐使用多重继承,这会增加程序的复杂度

 

标签:逆向,struct,Person,继承,age,C++,int,Teacher
From: https://blog.51cto.com/u_11908275/6941588

相关文章

  • C++逆向分析——this指针
    this指针概述C++是对C的拓展,C原有的语法C++都支持,并在此基础上拓展了一些语法:封装、继承、多态、模板等等。C++拓展新的语法是为了让使用更加方便、高效,这样就需要编译器多做了很多事情,接下来我们就需要一一学习这些概念。封装之前我们学习过结构体这个概念,那么结构体可以做参数传......
  • C语言逆向——预处理之宏定义、条件编译与文件包含
    预处理之宏定义、条件编译与文件包含预处理一般是指在程序源代码被转换为二进制代码之前,由预处理器对程序源代码文本进行处理,处理后的结果再由编译器进一步编译。预处理功能主要包括宏定义、文件包含、条件编译三部分。宏定义简单的宏:#define标识符字符序列#defineFALSE0#d......
  • C语言逆向分析——Switch语句,为何大多数情况较if语句更高效?就是因为查找表
    Switch语句Switch语句也是分支语句的一种,其语法如下:switch(表达式){case常量表达式1:语句;break;case常量表达式:语句;break;case常量表达式:语句;break;......default:语句;break;}需要注意如下几点:表达式结束不能是浮点数case后的常量......
  • C语言逆向——数组和结构体,数组多维只是一个编译构造的假象,本质会转成一维数组,结构体
    数组数组是C语言中非常重要的一个概念,学习C语言主要就是两个知识点:数组、指针,学好这两个,那么你的C语言一定也会很好。什么是数组?或者说什么情况下我们需要使用数组,比如说我们需要定义一个人的年龄,我们可以定义一个变量来表示,但是如果我们需要定义三个人的年龄呢?那就需要三个变量来......
  • 逆向——字符与字符串,中文字符GB2312编码由来
    字符与字符串在之前的课程中我们了解到变量的定义决定两个事情,第一是决定存储的数据宽度,第二是决定了存储的数据格式,那么我们来看下下面的代码:inta=123;//变量x,数据宽度为4个字节,里面存储的是补码(在计算机系统中,数值一律用补码来存储)intfloatb=123.4F;//IEEE编码(浮点)......
  • 【C++数据结构】启航,打开新世界的大门!
    @TOC一、学习数据结构的原因学习数据结构对于计算机科学和软件开发非常重要,它提供了处理和组织数据的有效方法和技术。以下是几个学习数据结构的重要原因:提高问题解决能力:数据结构教会了我们如何选择和使用适当的数据结构来解决问题。了解各种数据结构的特性和性能可以帮助我们分......
  • v_jstools js逆向分析工具
    1.工具地址:https://github.com/cilame/v_jstools2.下载文件文件下载下来以后,复制到桌面,然后解压到当前文件夹,会看到一个  v_jstools-main 的文件夹。3.插件安装谷歌浏览器地址栏输入如下url,打开扩展程序页面,并打开开发者模式:chrome://extensions/打开后,点击......
  • protobuf在c++中的使用
    一、安装sudoaptinstalllibprotobuf-devprotobuf-compiler二、编辑proto文件,生成代码文件proto语法分为“proto2”和”proto3“两个版本,指定方法是在proto文件中第一行写入:syntax="proto3";,这样指定使用proto3版本的语法,如果不指定,默认是使用proto2的语法。两个语法的......
  • Dao继承JpaRepository 、 JpaSpecificationExecutor 接口
    @RepositorypublicinterfaceUserRepositoryextendsJpaRepository<User,Integer>{xxx...}关于Dao继承JpaRepository:前要:Jpa:JPA是Spring提供的一种ORM,ORM:对象关系映射(ObjectRelationalMapping,简称ORM),简单的说,ORM是通过使用描述对象和数据库之间映射的......
  • C/C++ 数据结构五大核心算法之分治法
    分治法——见名思义,即分而治之,从而得到我们想要的最终结果。分治法的思想是将一个规模为N的问题分解为k个较小的子问题,这些子问题遵循的处理方式就是互相独立且与原问题相同。两部分组成:分(divide):递归解决较小的问题治(conquer):然后从子问题的解构建原问题的解三个步骤:1、......