BinFlip/undelphi

GitHub: BinFlip/undelphi

用于 Delphi / C++Builder / Free Pascal 编译二进制的 Rust 静态分析库,无需运行即可提取 RTTI、类层次、DFM 表单及嵌入资源等完整元数据。

Stars: 2 | Forks: 0

# undelphi [![Crates.io](https://img.shields.io/crates/v/undelphi.svg)](https://crates.io/crates/undelphi) [![License: Apache-2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) 用于已编译的 **Delphi**、**C++Builder** 和 **Free Pascal / Lazarus** 二进制文件的 Rust 静态分析库。它能够识别工具链,恢复完整的类层次结构和每个类的 RTTI,解析嵌入的表单流(form streams),并提取出运行时元数据可达的所有 blob 和交叉引用 —— 而无需执行二进制文件。 ``` use undelphi::DelphiBinary; let bytes = std::fs::read("my_app.exe")?; if let Ok(bin) = DelphiBinary::parse(&bytes) { if let Some(info) = bin.compiler() { println!("{:?} {} on {:?}/{:?}", info.compiler, info.raw, info.os, info.arch); } println!("{} classes, {} forms", bin.classes().len(), bin.forms().len()); } ``` ## 提取内容 ### 工具链识别 | 信号 | 置信度 | 恢复信息 | | --- | --- | --- | | Embarcadero 构建字符串 (`Embarcadero Delphi for Win64 compiler version 36.0 …`) | 高 | 精确的编译器版本 → 市场发布名称(例如 *Delphi 12 Athens*)、目标操作系统、目标架构 | | FPC 构建字符串 (`FPC 3.2.2 [2021/05/15] for i386 - Win32`) | 高 | FPC 版本、目标操作系统、目标架构 | | `DVCLAL` 资源 | 高 | SKU(个人版 / 专业版 / 企业版) | | `PACKAGEINFO` 资源 | 高 | unit 列表 + 所需 package 列表 | | `SOFTWARE\Borland\Delphi\RTL` 注册表路径 | 中 | XE2 之前的 Delphi(仅限年代) | | 带命名空间的 unit 名称 (`Vcl.Controls`, `System.SysUtils`, …) | 中 | XE2 或更高版本的 Delphi(仅限年代) | | `TPF0` 魔数(magic-byte)计数 | 中 | 非零 ⇒ 二进制文件包含表单(form-bearing) | | 验证后的 VMT 扫描 | 中 | 非空 ⇒ 在结构上属于 Delphi/FPC(即使所有字符串都被剥离) | ### 类发现 - 适用于 32 位和 64 位、跨 Windows PE / macOS Mach-O / Linux ELF 的 Delphi 和 FPC 布局的 **VMT 形状测试扫描器**。 - 带有 FPC `PClass` 风格间接回退的 **父类链解析**。检测外部父类(`vmtParent` 指向依赖 package 的 VMT),以便 BPL 运行时 package 能够清晰地报告为 `roots=0, external=N`,而不是出现大量孤立类。 - 按类名和 VMT 虚拟地址进行 **索引查找**。 - 类树渲染、祖先遍历(防止循环)、子类枚举、最大深度、根/孤儿/外部计数。 ### 每个类的元数据 对于每个发现的类: - **Published 方法** —— 名称 + 代码 VA,以及现代 Delphi 的扩展尾部。 - **Published 字段** —— 名称、相对于实例的偏移量、字段类型对应的已解析 `PPTypeInfo`。支持 Delphi 遗留字段表和现代字段表布局,以及 FPC 的 `TVmtFieldTable`。 - **Published 属性** —— 完整的 `TPropInfo`:PropType 指针、get/set/stored 访问器(Delphi field/virtual/static 或 FPC `ptField`/`ptStatic`/`ptVirtual`/`ptConst`)、Index、Default、NameIndex。 - **实现的接口** —— IID GUID(规范格式化)、vtable VA、实例偏移量、getter VA。FPC Corba 接口额外提取 `IIDStr` 名称。 - **虚方法指针表** —— 每个槽位一个条目,自动以下一个类的 VMT 基址为边界。 - **Init(受托管字段)表** —— 运行时进行引用计数管理(字符串、接口、动态数组、托管记录)的每个偏移量。 - **动态分发表** —— `dynamic` 和 `message` 槽位及其 ID 和处理程序 VA。 ### 各 Kind 的 RTTI 解码器 对我们实际遇到的每一种类型 Kind 进行完整的结构化解码: `tkClass` · `tkEnumeration` · `tkInteger` · `tkChar` · `tkWChar` · `tkFloat` · `tkSet` · `tkClassRef` · `tkDynArray` · `tkInterface` · `tkRecord` · `tkMethod` · `tkProcedure` · `tkLString` · `tkUString` · `tkWString`。 `decode_type_detail` 分发器遵循属性或字段的 `PPTypeInfo` 间接引用,并返回一个 `TypeDetail` enum,以便调用方可以直接匹配 Kind,而无需预先分发。Delphi 和 FPC 的字节值均受支持(FPC 重新排列了 `TTypeKind` enum —— `tkClass` 在 Delphi 中为 `7`,在 FPC 中为 `15`;两者均已针对 `reference/` 进行了验证)。 ### 扩展 RTTI (Delphi 2010+) - 针对超越经典仅 published 集合的属性,提供每个成员的 **可见性** 标志(private / protected / public / published)。 - **属性表** 解码器,支持提取构造函数参数(字符串 / 整数 / 原始字节)。 ### 表单流 完整的 **TPF0** 和 **TPF1** 二进制表单流解析器。遍历的来源: 1. PE `RT_RCDATA` 资源(Delphi / C++Builder / FPC Windows)。 2. FPC 内部资源树(`fpc.resources` / `.fpc.resources` —— Mach-O、ELF 以及未定义 `FPC_HAS_WINLIKERESOURCES` 的 FPC PE 构建版本)。 递归组件树,每个已文档化的 `TValueType`(Null、List、Int8/16/32/64、QWord、Single、Double、Currency、Date、Extended、String、Ident、LString、WString、UString、Utf8String、Binary、Set、Collection、Nil、True、False),filer 标志(`ffInherited`、`ffChildPos`、`ffInline`),以及处理起来棘手的带有 `vaList` 包装器的 Collection 语法(已针对 FPC `writer.inc` 进行了验证,并在回归测试中进行了复现)。 符号化的 `render` 模块根据声明的 RTTI 类型对原始值进行美化打印(例如输出 `Align = alClient` 而不是 `Align = 2`,输出 `BorderIcons = [biSystemMenu, biMaximize]` 而不是 `BorderIcons = 7`)。 ### 嵌入 blob 提取 `bin.blobs()` 遍历每个已解析的表单,提取每个 `vaBinary` 叶子节点,并根据魔数对其进行分类: ICO · CUR · BMP · PNG · JPEG · GIF · WebP · TIFF · ZIP · GZIP · 7Z · RAR · PDF · PE · ELF · Mach-O · WAV · MP3 · WMF/EMF · RIFF · ShortString。 每个 `EmbeddedBlob` 都携带其原始表单资源、点分组件路径、属性名称、前导字节分类以及原始字节切片(从输入中借用)。这对于恶意软件分类非常有用 —— 它可以直接提供一份现成的清单,列出二进制表单流中包含的所有被释放的图标、嵌入的脚本、打包的 payload 或隐藏的 PE 文件。 ``` use undelphi::DelphiBinary; let bin = DelphiBinary::parse(&bytes).unwrap(); for blob in bin.blobs() { println!("{:>6} bytes {:?} {}.{}", blob.data.len(), blob.kind, blob.path, blob.property_name()); } ``` ### 交叉引用 构建在已经提取的元数据之上,无需额外扫描二进制文件: - **接口实现者** —— `BTreeMap`。 - **DFM 类实例化** —— `BTreeMap`。 - **事件处理程序绑定** —— 每个表单中的每个 `OnClick` / `OnCreate` 等,并在处理程序可以链接到某个 published 方法时提供解析后的代码 VA(遍历该类的祖先链)。 - **每个 unit 的汇总统计** —— 类计数、字段 / 方法 / 属性 / 接口总数、每个声明 unit 的总实例字节数。 - **外部父类报告** —— 继承自依赖 package 导出 VMT 的本地声明类列表。 ### 实例内存布局 针对给定类逐字节重建实例 —— 将 published 字段表、init-table 受托管字段偏移量和声明的 `InstanceSize` 进行融合。标记命名字段、间隙(private/非 published 成员或填充)以及仅受托管条目(类保持为 private 的引用计数字段)。 ## 支持的目标 | 工具链 | 版本 | 容器 | | --- | --- | --- | | Embarcadero / Borland Delphi | Delphi 2 → Delphi 12 Athens (`dcc` v9 → v36) | PE32 / PE32+, Mach-O, ELF | | Embarcadero C++Builder | 解析方式与 Delphi 相同(使用相同的 VCL/FMX RTTI) | PE32 / PE32+ | | Free Pascal / Lazarus | FPC 1.0 → FPC 3.2+(包含处于 trunk 阶段的 3.3 版本) | PE32 / PE32+, Mach-O, ELF | | 架构 | x86, x86_64, ARM, AArch64 | (根据构建字符串和/或容器头文件判定) | ## 性能 在一个 25 MB 的 Delphi 12 Athens PE(`heidisql.exe` —— 包含 2,661 个类,42 个表单资源,以及数十万次 VA 解引用)上,在 release 模式下,于现代笔记本电脑上执行完整的解析 + `forms()` + 所有 `xref::*` 视图大约仅需 ~100 毫秒。 ## 示例 - [`examples/dump.rs`](examples/dump.rs) — 针对单个二进制文件的详尽元数据转储器。打印出该 crate 知道如何提取的每一项信息: cargo run --release --example dump -- path/to/binary.exe 基于 [Apache License, Version 2.0](LICENSE) 授权。
标签:Delphi, Rust, 云安全监控, 云资产清单, 元数据提取, 可视化界面, 网络流量审计, 进程保护, 逆向工程, 通知系统, 静态分析