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(多负载枚举布局)、ClassHierarchyDumper、MetadataReader。 |
SwiftDump | 高级类型包装器(Struct、Enum、Class、Protocol、ProtocolConformance、…)。 |
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、@nonobjc、dynamic、@retroactive、@globalActor、@escaping、consuming/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 SwiftInspection、MachOImage)。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 工具提供六个子命令:dump、interface、diff、snapshot、evolution 和 transformer。
[!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 - 自定义注释格式
内存布局注释 dump 和 interface 的输出是从 token 模板渲染而来。五种注释类型——字段偏移量、vtable 偏移量、成员地址、类型布局、枚举布局——各自拥有独立的模板、独立的 ${token} 占位符,以及一组可命名的内置模板。此子命令用于列出这些模板并构建可复用的配置;模板选项本身可直接由 dump 和 interface 接受。
# 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__/ 个文件与触发重新生成的源更改一起提交。
许可证
MachOSwiftSection 根据 MIT 许可证发布。请参阅 LICENSE