ITADN
MxIris-Reverse-Engineering/MachOSwiftSection
MxIris-Reverse-Engineering/MachOSwiftSection · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

MachOSwiftSection

一个用于解析 mach-o 文件以获取 Swift 信息的 Swift 库。 (类型/协议/协议一致性信息)

它可能是目前你能找到的最强大的 swift dump,因为它使用自定义的 Demangler 来解析符号引用,并尽可能恢复 Swift Runtime 的原始逻辑。

[!NOTE] 该库作为 MachOKit for Swift 的扩展进行开发

要求

  • Swift 6.2+
  • Xcode 26.0+
  • macOS 10.15+ / iOS 13+ / tvOS 13+ / watchOS 6+ / visionOS 1+

MachOSwiftSection 库

路线图

  • 协议描述符
  • 协议一致性描述符
  • 类型上下文描述符
  • 关联类型描述符
  • Dyld 缓存的方法符号
  • 内置类型描述符
  • Swift 接口支持
  • 运行时元数据检查 (SwiftInspection)
  • 类型成员布局 (WIP, 仅限 MachOImage)
  • Swift Section MCP

Swift Package Manager

将包添加到你的 Package.swift:

dependencies: [
    .package(url: "https://github.com/MxIris-Reverse-Engineering/MachOSwiftSection", from: "0.10.0"),
],
targets: [
    .target(
        name: "YourTarget",
        dependencies: [
            .product(name: "MachOSwiftSection", package: "MachOSwiftSection"),
            // Optional higher-level products:
            .product(name: "SwiftInspection", package: "MachOSwiftSection"),
            .product(name: "SwiftDump", package: "MachOSwiftSection"),
            .product(name: "SwiftInterface", package: "MachOSwiftSection"),
            .product(name: "TypeIndexing", package: "MachOSwiftSection"),
        ]
    ),
]
产品用途
MachOSwiftSection__swift5_* 部分的低级解析(原始描述符)。
SwiftInspection运行时元数据检查 — EnumLayoutCalculator(多负载枚举布局)、ClassHierarchyDumperMetadataReader
SwiftDump高级类型包装器(StructEnumClassProtocolProtocolConformance、…)。
SwiftInterface端到端的 Swift 接口生成。
TypeIndexing用于跨二进制分析的索引类型 / 扩展 / 一致性。

用法

基础

可以通过 swift 属性从 MachOImage 或 MachOFile 中获取 Swift 信息。

import MachOKit
import MachOSwiftSection

let machO //` MachOFile` or `MachOImage`

// Protocol Descriptors
let protocolDescriptors = try machO.swift.protocolDescriptors
for protocolDescriptor in protocolDescriptors {
    let protocolType = try Protocol(descriptor: protocolDescriptor, in: machO)
    // do somethings ...
}

// Protocol Conformance Descriptors
let protocolConformanceDescriptors = try machO.swift.protocolConformanceDescriptors
for protocolConformanceDescriptor in protocolConformanceDescriptors {
    let protocolConformance = try ProtocolConformance(descriptor: protocolConformanceDescriptor, in: machO)
    // do somethings ...
}

// Type/Nominal Descriptors
let typeContextDescriptors = try machO.swift.typesContextDescriptors
for typeContextDescriptor in typeContextDescriptors {
    switch typeContextDescriptor {
    case .type(let typeContextDescriptorWrapper):
        switch typeContextDescriptorWrapper {
        case .enum(let enumDescriptor):
            let enumType = try Enum(descriptor: enumDescriptor, in: machO)
            // do somethings ...
        case .struct(let structDescriptor):
            let structType = try Struct(descriptor: structDescriptor, in: machO)
            // do somethings ...
        case .class(let classDescriptor):
            let classType = try Class(descriptor: classDescriptor, in: machO)
            // do somethings ...
        }
    default:
        break
    }
}

生成完整的 Swift 接口

对于生成完整的 Swift 接口文件,你可以使用 SwiftInterface 库,它提供了更全面的接口生成功能。

import MachOKit
import SwiftInterface

let builder = try SwiftInterfaceBuilder(configuration: .init(), eventHandlers: [], in: machO)
try await builder.prepare()
let result = try await builder.printRoot()

生成的接口反映了广泛的 Swift 语言特性:

  • 类型 / 成员属性:@objc@nonobjcdynamic@retroactive@globalActor@escapingconsuming / borrowing 参数修饰符
  • distributed actor 声明和 distributed func 成员
  • 用于类和 noncopyable 类型的 deinit
  • 与类成员并列的 VTable 偏移注释,顺序与磁盘布局匹配
  • 嵌套结构体字段的展开字段偏移,以树形渲染
  • 类型和泛型要求上的反转协议(~Copyable~Escapable

检查运行时元数据

SwiftInspection 提供了构建在 MachOSwiftSection 之上的更高级别的检查工具:

  • EnumLayoutCalculator — 计算 Swift 枚举的磁盘布局,包括单负载和多负载(带标签和无标签)情况。镜像了 swift/ABI/Enum.h 中的 ABI 规则。
  • ClassHierarchyDumper — 遍历跨 Swift/ObjC 边界的类继承链(仅需要 @_spi(Internals) import SwiftInspectionMachOImage)。
  • MetadataReader — 对类型、符号、上下文描述符进行 demangle,并针对 Mach-O 构建泛型签名。

swift-section CLI 工具

安装

您可以通过三种方式获取 swift-section CLI 工具:

  • GitHub Releases:从 GitHub releases 下载
  • Homebrew:通过 brew install swift-section 安装
  • 从源码构建:使用 ./build-executable-product.sh 构建(需要 Xcode 26.0 / Swift 6.2+ 工具链)

用法

swift-section CLI 工具提供六个子命令:dumpinterfacediffsnapshotevolutiontransformer

[!IMPORTANT] 从 0.10.0 版本开始,当输入是 fat / universal 二进制文件时,您必须传递 --architecture <arch>。该工具不再静默选择默认切片。

dump - 转储 Swift 信息

从 Mach-O 文件或 dyld 共享缓存中导出 Swift 信息。

swift-section dump [options] [file-path]

基本用法:

# Dump all Swift information from a Mach-O file
swift-section dump /path/to/binary

# Dump only types and protocols
swift-section dump --sections types,protocols /path/to/binary

# Save output to file
swift-section dump --output-path output.txt /path/to/binary

# Use specific architecture (required for fat binaries)
swift-section dump --architecture arm64 /path/to/binary

静态内存布局注释(离线计算,未加载进程):

# Field offsets for struct/class stored properties
swift-section dump --emit-field-offsets /path/to/binary

# Field offsets + per-field type layout (size / stride / alignment)
swift-section dump --emit-field-offsets --emit-type-layout /path/to/binary

# Expand nested struct fields with their absolute offsets
swift-section dump --emit-expanded-field-offsets /path/to/binary

# Enum layout (strategy / per-case / spare bits)
swift-section dump --emit-enum-layout /path/to/binary

# Enum layout with a different comment style — detailed (default), explained
# (bit ranges in plain words), standard (no per-byte lines), inline (one line
# per case with the byte summary), or compact
swift-section dump --enum-layout-style explained /path/to/binary

上述每种注释类型都可以使用您自己的模板重新格式化——参见 transformer。传递模板 选项意味着匹配 --emit-… 标志。

这些偏移量由 SwiftLayout 引擎静态计算得出——无运行时、 无元数据访问器、不将二进制文件加载到进程中——因此它们适用于任何 磁盘上的 Mach-O 文件(包括弹性类和跨模块字段类型, 通过 dyld 共享缓存上的依赖闭包解析,以及 值通用和参数包实例化,例如 InlineArray<5, Int8>Variadic<Int, String> 字段)。 interface 命令的 --emit-offset-comments / --emit-expanded-field-offsets 标志使用相同的静态引擎。

处理 dyld 共享缓存:

# Dump from system dyld shared cache
swift-section dump --uses-system-dyld-shared-cache --cache-image-name SwiftUICore

# Dump from specific dyld shared cache
swift-section dump --dyld-shared-cache --cache-image-path /path/to/cache /path/to/dyld_shared_cache

转储输出包含更丰富的注释:

  • 协议见证表(PWT)条目标注了它们满足的要求
  • 反转的协议约束(~Copyable~Escapable)在类型和通用要求上呈现
  • 协议一致性可以包含 PWT 地址

interface - 生成 Swift 接口

从 Mach-O 文件生成完整的 Swift 接口文件,类似于 Swift 生成的接口。

swift-section interface [options] [file-path]

基本用法:

# Generate Swift interface from a Mach-O file
swift-section interface /path/to/binary

# Save interface to file
swift-section interface --output-path interface.swiftinterface /path/to/binary

# Use specific architecture (required for fat binaries)
swift-section interface --architecture arm64 /path/to/binary

静态内存布局注释:

# Field offsets (and PWT offsets) on the generated interface
swift-section interface --emit-offset-comments /path/to/binary

# Per-field type layout (size / stride / alignment) and enum layout
swift-section interface --emit-type-layout --emit-enum-layout /path/to/binary

这些使用与 dump 相同的静态 SwiftLayout 引擎,并接受相同的 注释模板选项 — 参见 transformer.

使用 dyld 共享缓存:

# Dump from system dyld shared cache
swift-section interface --uses-system-dyld-shared-cache --cache-image-name SwiftUICore

# Dump from specific dyld shared cache
swift-section interface --dyld-shared-cache --cache-image-path /path/to/cache /path/to/dyld_shared_cache

diff - 比较两个版本的 ABI

二进制层面比较同一模块两个版本的 Swift ABI —— 字段重类型、枚举案例标签重新编号、访问器变更、新增/移除的符合性 —— 这些细节是 .swiftinterface 差异无法看到的。扩展变更按每个符合性 / 每个条件块进行归因(Target: Protocol where …),因此添加或移除单个符合性被视为一个容器级别的变更。其需求符号被剥离的协议(操作系统框架的规范)仍通过其见证表槽位进行差异比较,因此协议增加或减少一个需求在零符号的情况下也是可见的;请比较处于相似剥离状态的二进制文件,因为符号丰富与已剥离的配对会将同一需求报告为成员交换。

# Change-list report with a breaking/backward-compatible verdict
swift-section diff old/Foo.framework/Foo new/Foo.framework/Foo

# Either side may be a persisted baseline produced by `snapshot`
swift-section diff baseline.json new/Foo.framework/Foo

# Machine-readable output / CI gating
swift-section diff old.dylib new.dylib --json
swift-section diff old.dylib new.dylib --summary-only --fail-on-breaking

# Full interface annotated with +/- diff markers (needs two binaries)
swift-section diff old.dylib new.dylib --interface --format unified

snapshot - 持久化 ABI 基线

对二进制文件进行一次性索引,并将其 ABI 冻结为版本化的 JSON 基线;后续的 diff 和 evolution 运行可以消费该 JSON,而无需原始二进制文件。

swift-section snapshot /path/to/binary --label 1.0 -o baseline-1.0.json

# From a dyld shared cache image
swift-section snapshot --dyld-shared-cache -n SwiftUICore /path/to/dyld_shared_cache --label 26.0 -o swiftuicore-26.0.json

evolution - 跨多个版本跟踪 ABI

按有序版本序列(从最旧开始)跟踪单个模块的 ABI,并报告每个声明的生命周期:引入 / 修改 / 移除 / 重新添加,并为每次转换提供附加性或破坏性判定。输入可自由混合二进制文件、dyld 共享缓存和 snapshot 基线。

# Three OS versions of the same framework, one report
swift-section evolution 17.0.json 18.0.json /path/to/Foo-26.0.dylib --labels 17.0,18.0,26.0

# Across dyld shared caches (extracts the same image from each cache)
swift-section evolution --dyld-shared-cache -n SwiftUICore cache-17 cache-18 cache-26

# Summary or JSON, and CI gating on any breaking transition
swift-section evolution v1.json v2.json v3.json --summary-only --fail-on-breaking
swift-section evolution v1.json v2.json v3.json --json

transformer - 自定义注释格式

内存布局注释 dumpinterface 的输出是从 token 模板渲染而来。五种注释类型——字段偏移量、vtable 偏移量、成员地址、类型布局、枚举布局——各自拥有独立的模板、独立的 ${token} 占位符,以及一组可命名的内置模板。此子命令用于列出这些模板并构建可复用的配置;模板选项本身可直接由 dumpinterface 接受。

# What can a template say?
swift-section transformer tokens                        # every module
swift-section transformer tokens --module enum-layout   # one module

# Built-in templates — their names are accepted by the template options
swift-section transformer templates --module field-offset

使用模板。 传入一个内置模板名称或包含 ${token} 占位符的字面量模板。未匹配到任何内容的名称将视为错误,而非静默地生成常量注释。

# Built-in template by name: "// 0x0 ..< 0x10"
swift-section dump --field-offset-template range /path/to/binary

# Literal template: "// @0x0"
swift-section dump --field-offset-template '@${startOffset}' /path/to/binary

# Enum layout is three templates: strategy line, per case, per fixed byte
swift-section dump \
    --enum-layout-template strategyOnly \
    --enum-layout-case-template inlineSummary \
    /path/to/binary

传递任何模板选项都会启用其对应的注释类型,因此无需单独的 --emit-… 标志。数字可以在每个模块中在十六进制和 十进制之间切换(--field-offset-hex / --no-field-offset-hex,以此类推)。

可复用配置。 一整套模板可以冻结到一个 JSON 文件中,并通过 --transformer-config 重放。该文件格式是 RuntimeViewer 持久化的格式,因此在 RuntimeViewer 设置界面中调整的配置在此处 可以原样使用。

# Freeze a command line into a file
swift-section transformer config \
    --field-offset-template range \
    --enum-layout-style compact \
    --output-path comments.json

# Replay it
swift-section dump --transformer-config comments.json /path/to/binary
swift-section interface --transformer-config comments.json /path/to/binary

运行测试

本仓库中的快照测试依赖于一个基于 Tests/Projects/SymbolTests/ 中的 Xcode 项目构建的 fixture 框架(SymbolTestsCore)。框架二进制文件未纳入版本控制——克隆后需重新构建一次:

./Scripts/build-test-fixtures.sh

然后运行测试:

swift package update
swift test

跳过 fixture 构建会导致 MachOFileTests 在测试 init() 期间,于 Tests/Projects/SymbolTests/DerivedData/.../SymbolTestsCore 处抛出 "file not found" 错误,且在任何断言执行之前。

在合法的 Swift 编译器 / 元数据变更后重新生成快照:

SNAPSHOT_TESTING_RECORD=all swift test \
    --filter SymbolTestsCoreDumpSnapshotTests \
    --filter SymbolTestsCoreInterfaceSnapshotTests

将更新后的 __Snapshots__/ 个文件与触发重新生成的源更改一起提交。

许可证

MachOObjCSection

MachOKit

CwlDemangle

MachOSwiftSection 根据 MIT 许可证发布。请参阅 LICENSE