C++逆向分析--虚函数(多态的前置)

先理解一件事,在intel汇编层面来说,直接调用和间接调用的区别。

直接调用语法: call 地址   硬编码为 :e8

间接调用语法:   call [ ...]     硬编码为:    FF

那么在C++语法中,实现多态的前提是父类需要实现多态的成员方法前面加入virtual。我们先来看一个例子,这次试验用的是windows平台下的VS编译器不同编译器的细节是不一样的原理大差不差。

#include<iostream>using namespace std;class Base {
public:void func1() {printf("这是func1");}virtual void func2() {printf("这是func2");}};int main() {Base b1;b1.func1();b1.func2();return 0;
}

  这个代码示例中我们只写了一个类,并且用对象去调用成员方法。运行结果如下:


我们观察下汇编代码:

此时均为e8-call,属于直接调用。接下来我们换一种调用方式,我们通过指针的方式去调用对象方法:

#include<iostream>using namespace std;class Base {
public:void func1() {printf("这是func1");}virtual void func2() {printf("这是func2");}};int main() {Base b1;Base* p;p = &b1;p->func1();p->func2();return 0;
}


运行结果没有变化,但是此时我们观察反汇编我们就发现了不一样的地方:


fun1就是普通的成员函数,反汇编依然是那样。但是我们看加入关键字的virtual变成虚函数后,汇编代码变化了。真正调用的其实是call eax这句汇编代码,我们看到他的硬编码是FF D0。说明他是个间接调用。我们可以理解这段反汇编代码,p是指向对象的首地址的也就是this指针。将this指针的第一项放入eax,又将eax的第一项复制给edx,此时将this指针给ecx(如果是linux平台g++编译this指针是赋值给rdi的 _x64情况下)最后将edx的第一项赋值给eax。最后去执行。这段翻译可能有点绕。可以自己去理解下。

现在我们知道虚函数,如果是通过对象去调用,和普通成员方法没什么区别,但是如果通过指针或者引用去调用。那么他就是个间接调用。一些细节后面再讲。

下面我们再分析一个问题,这个类到底有多大。

#include<iostream>using namespace std;class Base {
public:int a;int b;void func1() {printf("这是func1");}void func2() {printf("这是func2");}};int main() {//Base b1;//Base* p;//p = &b1;//p->func1();//p->func2();printf("Base结构体大小为=%d", sizeof(Base));return 0;
}

这个问题应该很简单,只算数据大小,int类型是占4个字节因此这个Base对象的大小应该是8,因为成员方法是在代码区的,这里其实跟C语言的结构体没什么不一样的:


那如果现在我们将其中一个成员方法改成虚函数呢?


神奇的一幕发生了,变成了12。

那是不是说类中每多一个虚函数,就会多4字节大小呢?(32位而言,64位就是8)

我们将fun1也变成虚函数:


我们看到没有变化。也就是说,跟你在类中定义多少个虚函数木的关系。那这多出来的4字节是个什么鬼东西呢?这就是我们接下来要探究的东西。


我们观察。现在没有任何函数的情况下,我们的类是这样布局的。 0x00cffb80也就是b1对象的首地址。

下面我们加入一个虚函数:


我们观察此时对象的内存布局:


什么都没有,接着往下走:


再往下走:


再往下走:


我们发现对象首地址存的不再是1。而是一个地址。那这个地址是什么呢?这就是我们接下来要探究的东西。写一个demo:

#include<iostream>using namespace std;class Base {
public:int a;int b;virtual void func1() {printf("这是func1");}};int main() {Base b1;b1.a = 1;b1.b = 2;Base* p;p = &b1;p->func1();return 0;
}

我们跟过去反汇编:



我们现在看这两行汇编的意思就很明朗了。

1.mov eax [p]   //将对象的this指针放入eax

2.mov edx [eax] //将this指针首地址里面存的虚函数表放入edx

3.mov ecx [p]   //将this指针传给ecx

3,mov eax ,[edx] //将虚函数表里的第一项放入eax

4.call eax //调用fun1函数。


相比看懂了上面的流程就明白了。总结图如下:


那我们能验证虚函数表中的函数就是我们的想要调用的函数嘛?demo如下:

#include<iostream>using namespace std;class Base {
public:int a;int b;virtual void func1() {printf("这是func1\n");}};int main() {Base b1;b1.a = 1;b1.b = 2;Base* p;p = &b1;p->func1();printf("b1对象的地址=%p\n", &b1);printf("虚函数表地址=%p\n", *((int*)&b1));printf("func1函数地址=%p\n", *((int*)*((int*)&b1)));int p2 = *((int*)*((int*)&b1));_asm {call p2;}return 0;
}

这里因为我是用32位写的demo因此我们用内联汇编测试下。代码逻辑就是取出虚函数表中的第一项,然后用汇编调用,看是否和我们用指针调用的是同一个函数运行结果如下:


通过这个实验我们确实验证了虚函数表中存的就是我们的虚函数的地址。这也是C++编译器实现多态的一个先提条件。

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

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

相关文章

「 网络安全术语解读 」通用攻击模式检举和分类CAPEC详解

引言&#xff1a;在网络安全领域&#xff0c;了解攻击者的行为和策略对于有效防御攻击至关重要。然而&#xff0c;攻击模式的描述和分类方式缺乏统一性和标准化。为了解决这个问题&#xff0c;MITRE公司创建了CAPEC标准&#xff0c;以提供一个共享和统一的攻击模式分类框架。 1…

一文让你彻底搞懂cookie和session产生漏洞的原理

首先让我们来看看登录的一般流程&#xff1a; 输入账号密码提交给后端&#xff1b;后端进行判断账号密码是否一致&#xff0c;这里的逻辑根据每个程序员的想法去写&#xff1b;如果通过2登录成功&#xff0c;跳转登录成功的页面&#xff1b; 如果通过2登录失败&#xff0c;跳转…

Tensorflow2.0笔记 - 范式norm,reduce_min/max/mean,argmax/min, equal,unique

练习norm,reduce_min/max,argmax/min, equal,unique等相关操作。 范数主要有三种&#xff1a; import tensorflow as tf import numpy as nptf.__version__#范数参考&#xff1a;https://blog.csdn.net/HiWangWenBing/article/details/119707541 tensor tf.convert_to_tensor(…

TensorRT英伟达官方示例解析(二)

系列文章目录 TensorRT英伟达官方示例解析&#xff08;一&#xff09; TensorRT英伟达官方示例解析&#xff08;二&#xff09; 文章目录 系列文章目录前言一、03-BuildEngineByTensorRTAPI1.1 建立 Logger&#xff08;日志记录器&#xff09;1.2 Builder 引擎构建器1.3 Netwo…

【GitHub项目推荐--Awesome-Go/Python/JavaScript/Java】【转载】

Awesome 译为令人惊叹的、极好的&#xff0c;GitHub 上有很多 Awesome 开头的开源项目。比如 Awesome-Go、Awesome-Python。 就像汇总常用的软件一样&#xff0c;GitHub上有大量的开源项目&#xff0c;开发者就会根据需要汇总一些常用的好用的资源&#xff0c;并且根据 Awesom…

OCP NVME SSD规范解读-7.TCG安全日志要求

在OCP NVMe SSD规格中&#xff0c;TCG的相关内容涉及以下几个方面&#xff1a; 活动事件记录&#xff1a; NVMe SSD需要支持记录TCG相关的持久事件日志&#xff0c;用于追踪固态硬盘上发生的与TCG安全功能相关的关键操作或状态变化&#xff0c;如启动过程中的安全初始化、密钥…

当键入网址后,到网页显示,其间发生了什么

解析 URL&#xff1a; 浏览器地址栏输入 URL&#xff0c;浏览器解析 URL&#xff0c;从而生成发送给 web 服务器的请求信息&#xff08;例如 www.example.com&#xff09;。 检查域名缓存&#xff1a; 浏览器查看浏览器缓存系统缓存路由缓存&#xff0c; 如有存在缓存&#x…

SQL注入实战:盲注

盲注&#xff1a; 1、当攻击者利用SQL注入漏洞进行攻击时&#xff0c;有时候web应用程序会显示&#xff0c;后端数据库执行SQL查询返回的错误信息&#xff0c;这些信息能帮助进行SQL注入&#xff0c;但更多时候&#xff0c;数据库没有输出数据web页面&#xff0c;这是攻击者会…

JRT集中打印

之前一直在夯实基础&#xff0c;现在是补demo的时段了。了解过检验集中打印的人知道&#xff0c;集中打印的逻辑有多复杂。既要考虑普通检验报告加上换页。又要考虑微生物报告加上换页&#xff0c;既有A5的报告&#xff0c;也有A4的报告&#xff0c;还要考虑A4打印两个组装A5时…

工程化代码管理高频面试题

1. git常用命令以及工作中都怎么工作 git init 初始化仓库 ​ git status 查看当前各个区域的代码状态。 ​ git log查看commit记录 ​ git reflog查看完整记录 ​ git add 添加工作区代码到暂存区 ​ Git commit 暂存区代码的提交 ​ git reset 代码的版本回退 ​ git stash …

《WebKit 技术内幕》学习之七(3): 渲染基础

3 渲染方式 3.1 绘图上下文&#xff08;GraphicsContext&#xff09; 上面介绍了WebKit的内部表示结构&#xff0c;RenderObject对象知道如何绘制自己&#xff0c;但是&#xff0c;问题是RenderObject对象用什么来绘制内容呢&#xff1f;在WebKit中&#xff0c;绘图操作被定…

finalshell连接linux的kali系统

kali的ssh服务似乎是默认关闭的&#xff0c;笔者在玩CentOS系统时可以直接用finalshell完成连接&#xff0c;但kali不行&#xff0c;需要先手动开启ssh服务。 开启kali的ssh服务 输入【ssh start】命令开启ssh服务&#xff0c;可以用【ssh status】命令查看ssh状态&#xff0c…

第40集《佛法修学概要》

请大家打开讲义第一百零六页。我们讲到大乘的果位。大乘佛法的修学跟小乘最大的差别&#xff0c;主要在于一句话&#xff0c;就是大乘佛法是一种“称性起修&#xff0c;全修在性”。大乘佛法的功德第一个“称性”&#xff0c;这个“称”就是随顺。我们一念明了的心&#xff0c;…

【数据结构】 链栈的基本操作 (C语言版)

目录 一、链栈 1、链栈的定义&#xff1a; 2、链栈的优缺点&#xff1a; 二、链栈的基本操作算法&#xff08;C语言&#xff09; 1、宏定义 2、创建结构体 3、链栈的初始化 4、链栈的进栈 5、链栈的出栈 6、获取栈顶元素 7、栈的遍历输出 8、链栈的判空 9、求链…

AtCoder Beginner Contest 337 A~G

A.Scoreboard(循环) 题意&#xff1a; 两个队伍进行 N N N场比赛。在第 i i i场比赛中 &#xff08; 1 ≤ i ≤ N &#xff09; &#xff08;1≤i≤N&#xff09; &#xff08;1≤i≤N&#xff09;&#xff0c;两队各得到 X i X_i Xi​和 Y i Y_i Yi​分。比赛结束后总分更高…

BACnet网关BL121BN 实现稳定可靠、低成本、简单的楼宇自控协议BACnet转OPC UA解决方案

随着楼宇自控系统的迅猛发展&#xff0c;人们深刻认识到在楼宇暖通行业中&#xff0c;实时、可靠、安全的数据传输至关重要。在此背景下&#xff0c;高性能的楼宇暖通数据传输解决方案——协议转换网关应运而生&#xff0c;广泛应用于楼宇自控和暖通空调系统应用中。 钡铼技术…

[反转链表] [合并两个有序链表][分割链表]

这里写目录标题 反转链表合并两个有序链表分割链表 反转链表 1、题目&#xff1a; 2.思路  思路1&#xff1a;建立一个newHead,取一个节点进行头插。具体做法如下&#xff01; 建立一个newHead(新头)&#xff0c;由于一个节点里面存的是下一个节点的地址&#xff0c;如果取…

VS2019查看文件编码格式

文件->高级保存选项 在这里可以看见现在的编码格式也可以修改编码格式 如果没有高级保存选项的话可以参考这篇博客进行设置

Vue (v-bind指令、el与data的两种写法、理解MVVM、数据代理、V-no事件处理、双向数据绑定V-model、登陆页面实现

V-bind指令 el与data两种写法 MVVM 数据代理 V-no事件处理 V-no用于监听DOM对象 双向数据绑定V-model v-model 指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定&#xff0c;根据表单上的值&#xff0c;自动更新绑定的元素的值。 按钮的…

激光雷达行业梳理1-概述、市场、技术路线

激光雷达作为现代精确测距和感知技术的关键组成部分&#xff0c;在近几年里取得了令人瞩目的发展。作为自动驾驶感知层面的重要一环&#xff0c;相较摄像头、毫米波雷达等其他传感器具有“ 精准、快速、高效作业”的巨大优势&#xff0c;已成为自动驾驶的主传感器之一&#xff…