菜单

C++类恢复

相关源文件

本页面描述了 Ghidra 的 C++ 类恢复系统,该系统通过分析二进制文件,利用运行时类型信息 (RTTI) 重构 C++ 类层次结构、继承关系、虚函数表和类成员数据。该系统支持 Visual Studio/Windows 和 GCC 编译的二进制文件,其中对 Windows 二进制文件的支持更为完善。

关于 Ghidra 中的通用面向对象分析,请参见高级分析功能 (#6)。

C++ 类恢复概述

C++ 类恢复系统分析已编译二进制文件中的 RTTI 结构,以恢复面向对象编程构件。它识别类层次结构、继承关系(包括虚继承)、虚函数表、构造函数、析构函数和类成员数据。恢复的信息将应用于程序,通过正确识别 this 指针、类方法和成员变量访问,使反编译代码更具可读性。

来源:Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java302-308 Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java95-98

支持的 RTTI 格式

Windows/Visual Studio RTTI

使用 Visual Studio(或面向 Windows 的 Clang)编译的 Windows C++ 程序使用一种特定的 RTTI 格式,其中包括

  • Complete Object Locator 结构,指向类型信息
  • Class Hierarchy Descriptor 结构,描述继承关系
  • Base Class Descriptor 数组,列出父类
  • 包含 RTTI 元数据的虚函数表

GCC RTTI

GCC 编译的二进制文件使用不同的 RTTI 格式,包含

  • 特殊的 typeinfo 类(__class_type_info__si_class_type_info__vmi_class_type_info
  • 引用 typeinfo 结构的虚表
  • 编码类关系的各种混淆名称和符号

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java44-58 Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java48-61

核心组件

RecoveredClass

RecoveredClass 对象表示一个重构的 C++ 类,包含以下信息:

  • 类名和命名空间
  • 虚函数表和虚函数
  • 父类和子类
  • 继承关系(单一继承、多重继承、虚继承)
  • 构造函数和析构函数
  • 类结构和成员数据

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClass.java32-197

RTTIClassRecoverer

抽象类 RTTIClassRecoverer 作为基于 RTTI 的类恢复的基类,针对不同的编译器格式有专门的实现:

  • RTTIWindowsClassRecoverer:处理 Windows/Visual Studio RTTI 格式
  • RTTIGccClassRecoverer:处理 GCC RTTI 格式

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java34-100 Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java39-100 46-143

类恢复过程

1. 定位 RTTI 结构

第一步是识别二进制文件中的 RTTI 结构

  • Windows:查找 Complete Object Locator 结构,这些结构指向 Class Hierarchy DescriptorBase Class Array 结构
  • GCC:查找特殊的 typeinfo 类(__class_type_info__si_class_type_info__vmi_class_type_info

2. 恢复类层次结构

利用 RTTI 信息,系统将:

  • 识别类之间的父子关系
  • 确定继承类型(单一继承、多重继承、虚继承)
  • 创建类层次结构图

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java138-141 Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java626-700

3. 识别构造函数和析构函数

系统根据以下信息识别构造函数和析构函数:

  • 对虚函数表的引用
  • 函数命名模式
  • 函数行为分析
  • 函数间的引用

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java153-155 Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java326-329

4. 创建和应用类结构

最后,系统会:

  • 为类创建数据类型
  • 从构造函数/析构函数中识别类成员数据
  • 构建虚函数表结构
  • 更新函数签名以包含正确的 this 参数
  • 将恢复的结构应用于程序

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java169-176 Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java208-248

运行类恢复脚本

类恢复的主要脚本是 RecoverClassesFromRTTIScript.java,它提供了几个选项:

选项描述
PRINT_CLASS_DEFINITIONS将类似 C 语言的类定义打印到控制台
PRINT_CLASS_INFO打印类信息(父类、子类、虚函数、成员数据)
PRINT_CLASS_HIERARCHIES打印每个类的层次结构
FIXUP_PROGRAM查找缺失的 RTTI 结构和潜在函数
BOOKMARK_FOUND_FUNCTIONS为已识别的构造函数/析构函数创建书签
GRAPH_CLASS_HIERARCHIES显示类关系的可视化图表
USE_SHORT_TEMPLATE_NAMES在结构字段中使用缩短的模板名称

当脚本运行时,它会:

  1. 验证程序并确保其包含 RTTI
  2. 根据程序类型(Windows/GCC)创建相应的恢复器
  3. 从 RTTI 恢复类信息
  4. 将恢复的信息应用于程序
  5. 可选地创建图表或输出

来源:Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java94-117 Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java164-343

应用函数签名更新

ApplyClassFunctionSignatureUpdatesScript.java 脚本在列表中修改函数签名时,更新数据类型管理器中的类函数定义。

来源:Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionSignatureUpdatesScript.java40-160

应用函数定义更新

ApplyClassFunctionDefinitionUpdatesScript.java 脚本在数据类型管理器中修改类函数定义时,更新列表中函数签名。

来源:Ghidra/Features/Decompiler/ghidra_scripts/ApplyClassFunctionDefinitionUpdatesScript.java40-119

绘制类层次结构图

GraphClassesScript.java 创建类层次结构的可视化图表,显示继承关系

在图中

  • 无继承关系的类有独特的样式
  • 单一继承的类有独特的样式
  • 多重继承的类有独特的样式
  • 虚继承以独特的边线样式显示

来源:Ghidra/Features/Base/ghidra_scripts/GraphClassesScript.java114-211

技术细节

Windows RTTI 结构

Windows RTTI 使用以下结构:

  • RTTI_Complete_Object_Locator:指向类型信息和类层次结构
  • RTTI_Class_Hierarchy_Descriptor:包含继承标志和基类数量
  • RTTI_Base_Class_Array:基类描述符指针数组
  • RTTI_Base_Class_Descriptor:关于基类的信息

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIWindowsClassRecoverer.java44-59

GCC RTTI 结构

GCC RTTI 使用:

  • __class_type_info:用于无继承的类
  • __si_class_type_info:用于单一继承的类
  • __vmi_class_type_info:用于多重继承或虚继承的类
  • 引用 typeinfo 结构的虚表

来源:Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIGccClassRecoverer.java48-66

局限性

  • Windows/Visual Studio RTTI 恢复比 GCC 更完善且经过更多测试
  • GCC 类数据类型仅能针对无虚继承的类进行完整恢复
  • 恢复质量取决于编译器优化级别和 RTTI 的存在
  • 模板类恢复可能不完整或名称过长
  • 一些构造函数或析构函数可能被错误地归类为“不确定”

来源:Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java16-51

实现架构

来源:Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java92-180 Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RTTIClassRecoverer.java34-95 Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java50-170