菜单

反编译器系统

相关源文件

Ghidra 的反编译器系统是其核心组件,负责将机器码转换为人类可读的类C代码。它负责分析低级程序表示、构建数据流图、应用转换以简化代码、恢复数据类型,并最终生成可读的高级代码。本文档概述了反编译器的架构、组件以及它们如何协同工作以产生反编译输出。

有关核心反编译过程的详细信息,请参阅Core Decompilation Process。有关处理器架构细节的信息,请参阅Processor Architecture Support

反编译器架构概述

Ghidra 反编译器被组织为一个转换流水线,逐步将机器码转换为高级类C代码。它以函数为单位进行操作,构建表示函数行为的数据结构,然后逐步将这些结构转换为更抽象的表示形式。

来源:Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh145-172 Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh74-86 Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh74-86

关键组件与数据流

反编译器操作多种核心数据结构,这些结构代表了所分析函数的不同方面。

来源:Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh86-100 Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh213-378 Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh120-190

基本数据结构

Varnode

Varnode 类是反编译器中表示值的基本数据结构。它可以表示:

  • 一个寄存器
  • 一个内存位置
  • 一个常量值
  • 一个临时变量

Varnode 具有以下关键属性:

  • 大小 (以字节为单位)
  • 存储位置 (地址空间 + 偏移量)
  • 数据类型
  • 定义 PcodeOp (如果已写入)
  • 从该 Varnode 读取的 PcodeOp 列表

来源:Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh213-378 Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_varnode.cc25-247

PcodeOp

PcodeOp 类表示中间表示中的操作。每个 PcodeOp 都具有:

  • 一个操作码 (来自 P-code 指令集)
  • 输入 Varnode
  • 一个可选的输出 Varnode
  • 一个地址 (对应于原始机器指令)

PcodeOp 通过它们的输入和输出 Varnode 形成一个有向图,表示函数的数据流。

来源:Ghidra/Features/Decompiler/src/decompile/cpp/op.hh180-290 Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_op.cc22-100

Funcdata

Funcdata 类是与单个函数关联的所有数据结构的中央容器。它管理:

  • Varnode (通过 VarnodeBank)
  • PcodeOp (通过 PcodeOpBank)
  • 基本块和结构化块 (控制流)
  • 函数原型信息
  • Heritage 系统 (用于 SSA 形式)
  • 符号表和局部变量

来源:Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh56-100 Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc1-200

反编译过程

反编译过程由几个主要阶段组成:

  1. P-code 生成:

    • 原始机器指令被翻译成 P-code,这是一种中间表示
    • P-code 操作是平台无关的
  2. SSA 构建 (静态单赋值,Heritage):

    • Heritage 系统将 P-code 转换为静态单赋值形式
    • 每个变量只被赋值一次
    • Phi 函数 (MULTIEQUAL 操作) 在控制流合并点插入
  3. 转换:

    • 多轮基于规则的转换简化并重构代码
    • 操作被组合成更有意义的表达式
    • 消除公共子表达式
  4. 类型分析与传播:

    • 通过数据流推断和传播类型
    • 分析并恢复函数签名
    • 识别复杂数据结构
  5. 控制流分析:

    • 基本块被结构化为高级构造 (if/else、循环、switch)
  6. 变量合并:

    • 相关的 Varnode 被合并为高级变量
    • 寄存器和栈位置被转换为命名变量
  7. C 代码生成:

    • 具有恢复类型的简化结构化代码被转换为 C 语法
    • PrintC 类负责格式化和输出

来源:Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh34-86 Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh16-30 Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc122-140

转换系统

反编译器应用了大量的转换,将低级 P-code 表示转换为更高级别的构造。这些转换被组织为规则,用于识别特定模式并用简化版本替换它们。

来源:Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh86-250 Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh87-120 Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc212-266

转换示例包括:

  • 将位操作转换为更高级别的操作
  • 简化算术表达式
  • 识别常见模式 (例如,循环、函数调用)
  • 从指针算术中恢复结构访问
  • 传播常量并消除死代码

类型系统

反编译器的类型系统负责管理数据类型及其关系。它支持:

  • 基本类型 (整数、浮点数、指针)
  • 复杂类型 (结构体、联合体、数组)
  • 类型继承和组合
  • 通过表达式进行类型传播

来源:Ghidra/Features/Decompiler/src/decompile/cpp/type.hh175-300 Ghidra/Features/Decompiler/src/decompile/cpp/type.cc126-205 Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc25-70

代码生成 (PrintC)

反编译的最后阶段是生成人类可读的类C代码。PrintC 类负责:

  • 将结构化函数表示转换为 C 语法
  • 根据运算符优先级正确格式化表达式
  • 输出带有适当类型的变量声明
  • 生成控制流结构 (if/else、循环、switch)
  • 处理注释和注解

来源:Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh120-190 Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc122-140

SubvariableFlow:逻辑变量恢复

SubvariableFlow 类是一个专门组件,用于处理将较小逻辑值存储在较大容器中的情况 (例如,寄存器中的单个位或字中的一个字节)。它:

  1. 跟踪逻辑值通过操作的流向
  2. 创建一个仅表示逻辑值流向的子图
  3. 将容器上的操作替换为对逻辑值更直接的操作

这种转换有助于简化那些使用位操作来处理较大存储单元中较小值的代码。

来源:Ghidra/Features/Decompiler/src/decompile/cpp/subflow.hh25-50 Ghidra/Features/Decompiler/src/decompile/cpp/subflow.cc55-150

与 Ghidra 框架集成

反编译器通过多个接口与 Ghidra 的其他部分集成:

  1. 反编译器接口:

    • 提供反编译器功能的访问
    • 管理函数的反编译请求
    • 将结果返回给用户界面
  2. Clang 令牌管理:

    • 弥合反编译代码文本与原始程序位置之间的差距
    • 实现反编译代码与汇编代码之间的导航
  3. 程序数据库集成:

    • 访问程序符号、类型和内存
    • 用反编译器发现的信息更新数据库
  4. 扩展点:

    • 允许添加自定义处理器
    • 支持自定义反编译器转换
    • 支持基于脚本与反编译器进行交互

来源:Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc34-50

总结

Ghidra 反编译器系统是一个复杂的转换流水线,逐步将机器码转换为可读的类C代码。它通过以下方式运作:

  1. 构建函数操作和数据流的精确表示
  2. 应用转换以简化和结构化代码
  3. 恢复数据类型和变量关系
  4. 生成人类可读的输出

其模块化设计允许自定义和扩展,以支持不同的架构和语言特性,使其成为逆向工程复杂软件的强大工具。