发布时间:2026/9/6 6:48:29
C++逆向分析--虚函数(多态的前置) 先理解一件事在intel汇编层面来说直接调用和间接调用的区别。直接调用语法 call 地址 硬编码为 e8间接调用语法: call [ ...] 硬编码为: FF那么在C语法中实现多态的前提是父类需要实现多态的成员方法前面加入virtual。我们先来看一个例子这次试验用的是windows平台下的VS编译器不同编译器的细节是不一样的原理大差不差。#includeiostream 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属于直接调用。接下来我们换一种调用方式我们通过指针的方式去调用对象方法:#includeiostream 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。最后去执行。这段翻译可能有点绕。可以自己去理解下。现在我们知道虚函数如果是通过对象去调用和普通成员方法没什么区别但是如果通过指针或者引用去调用。那么他就是个间接调用。一些细节后面再讲。下面我们再分析一个问题这个类到底有多大。#includeiostream 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#includeiostream 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指针放入eax2.mov edx [eax] //将this指针首地址里面存的虚函数表放入edx3.mov ecx [p] //将this指针传给ecx3,mov eax ,[edx] //将虚函数表里的第一项放入eax4.call eax //调用fun1函数。相比看懂了上面的流程就明白了。总结图如下那我们能验证虚函数表中的函数就是我们的想要调用的函数嘛demo如下#includeiostream 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编译器实现多态的一个先提条件。

相关新闻

2026/9/6 6:47:15

蒸汽流量计最好的品牌排名 2026高温工况性能与服务对比

蒸汽是工业核心能源介质,计量的准确性与可靠性直接影响能耗核算、成本管控、贸易结算公平性与生产安全。蒸汽工况普遍高温高压、温度压力波动大、管道振动普遍,对流量计的精度、稳定性、耐温性、可靠性提出极高要求。所谓“最好的品牌”,核心…

2026/9/6 6:47:15

存储芯片封装设备常见问题答疑:产线工程师的实用避坑手册

干过封装这行的都知道,存储芯片封装设备的选型和调试,从来不是看参数表就能搞定的事。温度曲线偏一度、真空度差一个数量级,良率就能给你脸色看。今天不聊虚的,直接把产线上被问烂了的高频问题拎出来,一个个掰开揉碎讲…

2026/9/6 6:47:15

案例2.1《字体和文本样式设置》改写实践

# 微信小程序实训:案例 2.1《字体和文本样式设置》改写实践> 本文是《微信小程序开发》课程案例 2.1 的改写练习。记录如何将 WXML 中的静态内联样式抽取为 WXSS 的 class,并补充内容使页面支持滚动显示。## 一、案例背景教材案例"字体和文本样式…

2026/9/6 6:47:15

轻松学习TFLM_day9

STM32 TinyML Sine 工程总结 1. 工程概览 本工程运行在 STM32F303RETx(Cortex-M4)上,使用 TensorFlow Lite for Microcontrollers(TFLM)执行一个正弦波回归模型。固件每次输入一个角度对应的弧度值,模型输出…

2026/9/6 6:42:15

Manus恢复独立运营背后:AI Agent技术架构与工程化实践全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/6 0:06:59

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/6 0:06:59

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/6 0:06:59

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/6 0:06:59

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/6 0:06:59

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/6 0:06:59

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/5 2:45:13

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/5 2:30:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/5 2:46:50

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…