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

发布时间:2026/11/5 7:59:22

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/10/25 6:11:50

3分钟极速部署:Windows 11 LTSC一键恢复微软商店的完美方案

3分钟极速部署:Windows 11 LTSC一键恢复微软商店的完美方案 【免费下载链接】LTSC-Add-MicrosoftStore Add Windows Store to Windows 11 24H2 LTSC 项目地址: https://gitcode.com/gh_mirrors/ltscad/LTSC-Add-MicrosoftStore 你是否在使用Windows 11 LTSC系…

2026/11/5 7:58:11

jvm中的强软弱虚4种引用类型与gc的关系

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

2026/11/5 7:58:11

小白程序员轻松入门大模型,AI大数据开发工程师进阶指南

本文深入剖析AI大数据开发工程师的核心能力与岗位需求,对比传统大数据工程师,指出Spark/Flink等基础技能已不再是优势。文章详细解析了三类典型岗位(业务型、模型导向型、AI数据基础设施工程师)的选拔逻辑,并总结了企业…

2026/11/5 7:58:11

FHE层级

全同态加密的概念同态:密文计算的结果解密后,等于明文计算的结果。即 Dec(Enc(a)⊕Enc(b))ab全同态:支持任意深度的加法和乘法运算(不仅是单一操作,而且可以无限次组合)。第一层:密码学基础与底…

2026/11/5 7:58:11

【随笔1102】LangGraph 时间旅行

一、LangGraph是什么 顾名思义,就是一种适用于AI大模型运行的图结构。 你可以在图里声明节点(官方说是超级节点 Super Step) 节点也分为多种类型,比如Agent Node,调用大模型,按照提示词执行;还有…

2026/11/5 7:53:11

网页视频资源嗅探:不开抓包工具,5 分钟下走视频直链

网页视频资源嗅探:不开抓包工具,5 分钟下走视频直链 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 猫抓(cat-c…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

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

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑