【C++逆向】虚表(Virtual table)逆向 | 安卓so虚函数逆向

news2024/11/17 23:26:53

什么是多态

定义一个虚基类ISpeaker

class ISpeaker{
protected:
	size_t b;
public:
	ISpeaker( size_t _v )
		: b(_v) 
	{}
	virtual void speak() = 0;
};

有两个子类,都实现了虚函数speak():

class Dog : public ISpeaker {
public:
	Dog()
		: ISpeaker(0)
	{}
	//
	virtual void speak() override {
		printf("woof! %llu\n", b);
	}
};

class Human : public ISpeaker {
private:
	size_t c;
public:
	Human()
		: ISpeaker(1)
		, c(2)
	{}

	virtual void speak() override {
		printf("hello! %llu\n", c);
	}
};

main方法中把Dog*和Human*类型的指针,退化(强转)成ISpeaker*指针,并调用speak()方法:

int main( int argc, char** _argv ) {
	Human* pHuman = new Human();
	Dog* pDog = new Dog();
	//
	ISpeaker* speaker1 = (ISpeaker*)pHuman;
	ISpeaker* speaker2 = (ISpeaker*)pDog;
	//
	speaker2->speak();
	speaker1->speak();
	//
	return 0;
}

输出:

woof! 0
hello! 2

同样类型的指针(都是ISpeaker*),其函数表现出不同的行为(输出不同),称为多态

编译器如何实现多态

以MSVC编译器为例
在这里插入图片描述
编译器处理虚类ISpeaker时,生成内存模型(结构体)__ispeaker,其成员有虚表指针SpeakerTable* vt

Dog继承ISpeaker,所以对应的虚表类__dog会包含__ispeaker中的成员;
Human继承ISpeaker,所以对应的虚表类__human会包含__ispeaker中的所有数据,此外还有自己的数据size_t c
在这里插入图片描述
而后,编译器为每个类生成唯一的虚表实例
__dogSpeakerTable和__humanSpeakerTable是虚表实例

虚表实例中的函数指针指向对应的函数
在这里插入图片描述
所以Dog和Human,对应的 虚表实例 中的函数指针指向的函数不同。

这就是为什么speaker2->speak();speaker1->speak();的输出不同。

在内存中,__dog和__humen的布局如下:

struct __dog {
	const SpeakerTable* vt;
	size_t b;
};

struct __human {
	const SpeakerTable* vt;
	size_t b;
	size_t c;
};

因此,想访问b或者c成员时,是按虚表对象之后的偏移量来访问的。

调用__dog_speak和__human_speak时会传递对象__dog和__human作为参数:

int main( int _argc, char** _argv ) {
    __dog* dog = createDog();
	__human* human = createHuman();
	//
	__ispeaker* speaker1 = (__ispeaker*)dog;
	__ispeaker* speaker2 = (__ispeaker*)human;
	//
	speaker1->vt->speak(speaker1);
	speaker2->vt->speak(speaker2);
	return 0;
}

访问b或c对象时,基于偏移量:

void __dog_speak( void* _ptr ) {
	uint8_t* p = (uint8_t*)_ptr;
	p+=sizeof(SpeakerTable*);
	size_t b = *((size_t*)p);
	printf("woof! %llu\n", b);
}

void __human_speak( void* _ptr ) {
	uint8_t* p = (uint8_t*)_ptr;
	p+=sizeof(SpeakerTable*);
	p+=sizeof(size_t);
	size_t b = *((size_t*)p);
	printf("hello! %llu\n", b);
}

例如 uint8_t* p = (uint8_t*)_ptr;拿到__dog对象的起始偏移,
p+=sizeof(SpeakerTable*);是越过虚表对象,
size_t b = *((size_t*)p);就找到b对象了。

反编译so时虚函数调用长什么样

在这里插入图片描述


参考:
http://showlinkroom.me/2017/08/21/C-%E9%80%86%E5%90%91%E5%88%86%E6%9E%90/

https://www.bilibili.com/video/BV15g4y1a7F3/?spm_id_from=333.337.search-card.all.click&vd_source=0fcfb2f2f346ba4bccf7f3ee3eb4ae69

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1581_AURIX_TC275_SMU故障处理梳理

全部学习汇总: GreyZhang/g_TC275: happy hacking for TC275! (github.com) 前面为了缓解自己的学习压力,一次学习笔记大概也就是看10页文档整理一下。这一次其实是看了几十页,但是里面过掉了一些信息,而且这部分内容不是很好拆分…

hive在IDEA中debug

一、hive在IDEA中debug 安装hadoop环境(1和2替换顺序也可以) 注:hadoop环境不需要从源码编译 https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/SingleCluster.html 按照官网教程编译源码 https://cwiki.apach…

软件工程专业课实验报告

一、结构化分析方法1.1需求描述教务管理子系统的需求描述:教务管理是一项需求周密计划、严谨安排的工作,要依据教师、学生信息进行合理安排。开学阶段,需要教师提交开课申请进行开课,学生根据老师的开课信息,选择课程&…

uview 使用遇到的问题。

uviewuniappvue,uView是uni-app生态专用的UI框架。 1. 注意uview版本,uview 2.0与uview1.0 官方提示:uView2.0是继1.0以来的一次重大更新,2.0已全面兼容nvue。 因此在接手项目的时候首先得看清楚,之前开发的是uview…

【自学Python】Python获取字符串长度

Python获取字符串长度 Python获取字符串长度教程 在 Python 中要想获取 字符串 长度可以使用 len() 函数。 Python len()函数详解 定义 我们将要获取的字符串的长度,传进 len() 函数,即可实现获取字符串的长度。 语法 len(string)参数 参数描述s…

【7】K8s_Ingress | Service的统一网关入口

目录 1、Ingress简介 2、安装ingress 【1】制作ingress.yaml文件并执行 【2】测试,创建一个test.yaml文件并执行 【3】设置域名访问,用yaml文件 【4】路径重写 【5】流量限制 1、Ingress简介 Ingress: Service的统一网关入口是k8s中的一个api对象&…

时序数据库TDengine基本概念和建模思路

目录 一 、 时序数据库基本概念 采集量 标签 数据采集点 表 超级表 子表 库 二、 TDengine数据库建模策略 建表模式建表情形 行列数据库存储的区别: 接触的传统业务的数据模式都是行存储,我们会把不同类型的对象创建不同的表进行存储他们各自的属…

机器学习公式推导与代码实现-无监督学习模型

聚类分析与k均值聚类算法 督学习算法。在给定样本的情况下,聚类分析通过度量特征相似度或者距离,将样本自动划分为若干类别。 距离度量和相似度度量方式 距离度量和相似度度量是聚类分析的核心概念,大多数聚类算法建立在距离度量之上。常用的距离度量方式包括闵氏距离和马…

linux系统中使用QT来实现数据库的调用方法

大家好,今天主要和大家分享一下,如何使用QT中数据库的使用方法。 目录 第一:数据库基本简介 第二:数据库表格基本操作 第三:数据库最终效果 第一:数据库基本简介 数据库是按照数据结构来组织,…

视频目标检测与轨迹跟踪代码案例

前言通过阅读相关文献及测试,找到了一种基于多模板匹配的改进方法,可以对遥感视频卫星中的移动目标进行探测,并绘制其轨迹。根据实验结果发现,可以比较有效的对运动目标进行跟踪。一、原理核心思想比较简单。即通过不同旋转角度的…

AQS之ReentrantLock详解

非公平锁加锁过程一般我们在使用ReentrantLock的时候,代码如下:Test public void test(){ReentrantLock lock new ReentrantLock();lock.lock();try{//编写业务逻辑}catch (Exception e){lock.unlock();} }当我们在用ReentrantLock独占锁的时候&#xf…

current并发包

并发包 current并发包、在JDK1.5之前Java并没有提供线程安全的一些工具类去操作多线程,需要开发人员自行编写实现线程安全,但仍然无法完全避免低性能、死锁、资源管理等问题。在JDK1.5时新增了java.util.current并发包,其中提供了许多供我们…

【自学Python】Python截取字符串

Python截取字符串 Python截取字符串教程 在 Python 中,我们需要截取 字符串,不需要使用特定的 函数,只需要使用下标索引加上切片的形式,就可以实现字符串的截取。 Python字符 Python 中没有单个字符的概念,单个字符…

uni-app 微信小程序通过Vue3 Hooks 实现动态填充页面剩余高度

应用场景 在uni-app开发微信小程序等项目时,经常会遇到这样的页面布局需求:上半部分高度固定,下半部分自动占满剩余高度,如下图所示应用场景:上半部分为固定高度或内容填充高度的内容区域下半部分为scroll-view滑动区…

河北稳控科技振弦采集模块配置工具VMTool的常见功能

河北稳控科技振弦采集模块配置工具VMTool的常见功能 一、实时数据读取 当 VMTool 与模块为连接状态时( 4.3.1 模块的连接与断开), 勾选实时数据区的【 自动读取】 复选框, VMTool 开始自动向模块发送实时数据读取指令&#xff0c…

如何用 Java 来构建一个简单的速率限制器?

速率限制 现实世界中的用户是残暴的,并且没耐心,充满着各种不确定性。在高并发系统中,可能会出现服务器被虚假请求轰炸的情况,因此您可能希望控制这种情况。 一些实际使用情形可能如下所示: API配额管理-作为提供者…

28.函数指针变量作为函数的参数,容易混淆的指针概念,特殊指针,main函数传参

1.函数指针变量作为函数的参数 #include<stdio.h> int add(int x, int y) {return x y; } int sub(int x, int y) {return x - y; } int mux(int x, int y) {return x * y; } int dive(int x, int y) {return x / y; } int process(int(*p)(int, int),int x,int y) {in…

Redis基础命令操作三之集合类型SET

SET集合 特点&#xff1a;集合中存储的元素是惟一的。 命令举例说明SADD sadd [key] [value1 value2 value3]key对应的集合中添加元素SMEMBERSsmembers [key]获取key对应的集合的所有元素SISMEMBERsismember [key] [value]判断value是否在key对应的集合中存在SCARDscard [key…

excel日期函数:EDATE与DATE到底谁更胜一筹

平时的工作中&#xff0c;经常会遇到计算职工转正日期、合同到期日、职工退休日期以及产品有效期截止日等等与日期有关系的问题。这些问题看似复杂&#xff0c;实际上只需要一个很简单的函数就能搞定&#xff0c;这个函数就是EDATE。今天分享EDATE函数的几个应用实例&#xff0…

【Linux】Linux 权限和权限管理

文章目录Linux权限的概念Linux权限管理文件访问者的分类&#xff08;人&#xff09;文件类型和访问权限&#xff08;事物属性)目录权限默认权限粘滞位关于权限的总结Linux权限的概念 权限是用来限制人的&#xff0c;权限人事物属性 权限存在的意义是便于系统安全管理的 Linux下…