关于 re-swift
re-swift 是用于分析 Swift 编译产物的逆向技能,适合需要还原符号、协议分发表、闭包捕获和类型结构的分析者。它结合 mangling 解码与反射元数据,并覆盖 Swift 与 ObjC 的互操作分析。
主要功能
- 01识别 Swift 产物与反射段
- 02批量解码 mangled 符号
- 03恢复协议 witness table 关系
- 04分析闭包捕获上下文
- 05利用反射元数据还原类型布局
适用场景
- 01为反编译结果恢复 Swift 函数名
- 02分析协议一致性及动态分派
- 03从闭包上下文追踪捕获变量
- 04分析 Swift 与 ObjC 混合二进制
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dslsdzc/ rev-skills --skill re-swift安装后在 Claude Code 中输入/re-swift确认已加载。
附带文件references/examples.mdreferences/layout.md
详细介绍
来自项目 READMESwift 逆向
何时使用 / 何时不用
- 用:Swift 产物(Mach-O/ELF 含 Swift mangling 特征
$s前缀,或__swift5_*反射段),需要还原符号/协议一致性/闭包结构 - 用:混合产物中区分 Swift 层与 ObjC/C 层(先走 ObjC 路径再进 Swift 层)
- 不用:纯 ObjC(走 [[re-ios]] / [[re-macos]] 的 ObjC 路径);纯 C/C++(走 [[re-cpp-abi]])
- 不用:只需普通反编译([[re-ghidra]] / [[re-ida]] 直接上)
工具准备
swift-demangle(Swift 工具链,mangling 解码)
- macOS: Xcode 自带(
xcrun swift-demangle);Linux: Swift 官方工具链(swift.org 下载 tar 包解压即用,含swift-demangle);Windows: Swift 官方工具链 - 验证:
echo '$s4main6myFuncyyF' | swift-demangle(macOS 用xcrun swift-demangle;无参数时读 stdin,输出$s... ---> main.myFunc() -> ()) - 批量:
llvm-nm sample | swift-demangle;-simplified出精简名;-expand出解码树
swiftc / swift(可选,对照编译)
- macOS: Xcode 自带;Linux/Windows: 同上官方工具链(含编译器,可本地编译同版本样本对照符号形态)
- 验证:
swift --version
llvm-nm / llvm-objdump(符号与段)
- 安装与验证见 [[re-cpp-abi]] 工具准备;Mach-O 侧额外需要 otool(见 [[re-format-macho]] 工具准备)
- 用途:
llvm-nm -m sample看符号与段归属;otool -l sample | grep swift5定位反射段
Ghidra / IDA(反编译底座)
- 安装与验证见 [[re-ghidra]] / [[re-ida]];Swift 符号解码结果用于批量重命名(Ghidra 可脚本化:demangle 输出写回 symbol 表,反编译视图即恢复可读函数名)
操作步骤
按顺序执行,每步产物存档(路径 + sha256,见 [[re-triage]])。
-
产物识别:
strings -a sample | grep -E '^\$s|^_T0|^_\$S' | head llvm-nm sample 2>/dev/null | grep -E 'swift_|^\$s' | head # ELF 用 readelf -s 同效果 otool -l sample 2>/dev/null | grep -c swift5 # Mach-O 反射段存在性$s(Swift 5+)、$S(Swift 4.2)、_T0(Swift 4.0)是三代 mangling 前缀;swift_*运行时导入(swift_retain / swift_release / swift_allocObject)确认运行时- 纯 ObjC 无上述特征 → 转 [[re-ios]] / [[re-macos]];带
__swift5_*段但 strip 了符号名 → 仍是 Swift(反射元数据不随 strip 消失,见坑 5)
-
mangling 解码(批量):
llvm-nm -m sample | awk '$3 ~ /^\$s/ {print $3}' | swift-demangle | head -20 # ELF: readelf -s sample | awk '$8 ~ /^\$s/ {print $8}' | swift-demangle解码内容:模块名/类型/函数签名/泛型参数展开;结果写入符号表供 [[re-ghidra]] / [[re-ida]] 重命名。mangling 结构速览见步骤 3 与 [[layout]]。
-
mangling 结构速览(手读符号):
$s 前缀 + 长度前缀标识符 + 类型字母 + 签名 $s 13ExampleModule 3Foo C 3bar Si y F └模块(13字符) └类型 └类 └方法 └结果 └参数 └函数 C=类 O=枚举 V=结构体 P=协议;Si=Int SS=String Sq=Optional;y=空元组 ()编码规则:标识符=十进制长度+ASCII;签名顺序是结果类型在前、参数在后,
F结尾表示函数;签名可带修饰位(async/throws,解码输出中显式出现);_To后缀=@objc 桥接 thunk;TE后缀=distributed thunk。详细规则与官方示例见 [[layout]]/[[examples]]。 -
协议 witness table(动态分派核心):
- witness table 是协议方法的分发表;conformance 记录定位:Mach-O
__swift5_proto段 / ELFswift5_protocol_conformances(协议描述符在__swift5_protos/swift5_protocols),或搜索_swift_getWitnessTable调用点 - 还原:conformance 记录 = 方法槽位数组,槽值 = 对应协议要求的实现地址 → 结合 [[re-cpp-abi]] 的 vtable 恢复思路反推"哪个类型 conforms 哪个协议"
- 无符号名时用协议方法调用点反推:找到 witness method 调用处的函数指针表,表序即协议声明序
- 注意间接 conformance(
witness_table_indirect标志):槽位存的是间接表指针而非直接实现地址,需再解一层
- witness table 是协议方法的分发表;conformance 记录定位:Mach-O
-
闭包捕获:
- 闭包是 context 对象:
swift_allocObject调用点 → context 分配 → 捕获字段初始化;context 头部是指向捕获布局描述符的指针,其后按捕获顺序排列字段 - 还原:context 结构体字段 → 捕获变量名/类型(与函数签名关联);引用语义字段由
swift_retain/swift_release调用点确认 - 编译器生成的"partial apply forwarder"符号(解码含
partial apply forwarder)是闭包入点的典型形态
- 闭包是 context 对象:
-
ObjC 互操作:
@objc桥接:Swift 类经 ObjC runtime 可见(NSObject 子类、消息发送 objc_msgSend);Swift 侧实现入口是_To结尾的桥接 thunk- 分析:ObjC 方法列表(class-dump 思路)→ 桥接 thunk → Swift 实现;
swift_运行时函数调用点区分 Swift 侧逻辑 - 混合产物:先走 ObjC 路径([[re-ios]] / [[re-macos]])再进 Swift 层;Linux 上的 Swift 产物无 ObjC 层(无 __objc_classlist),纯 ELF 视角分析
-
反射元数据(类型结构还原):
otool -l sample | grep -A2 swift5_fieldmd # 字段描述(类型内布局) otool -l sample | grep -A2 swift5_typeref # 类型引用(字符串池) otool -l sample | grep -A2 swift5_reflstr # 反射字符串__swift5_fieldmd记录类型字段名/类型引用;配合__swift5_typeref可还原结构体/类布局,比纯反编译更快。 -
符号化恢复:解码结果批量重命名后,泛型特化符号(大量
Gy后缀)按模块/类型聚类过滤,先恢复"每个类型的核心方法"再处理特化副本(见坑 2)。 -
字节级核对:符号提取/段定位输出异常时,用
xxd按字节核对(mangled 名是长度前缀+ASCII,反射段是数据段内的定长记录)——最小字节样例与核对流程见 [[examples]],别把工具解析失败当"非 Swift 产物"丢弃。
跨域联合
- [[re-binary-core]] 网关:本技能归属(选择树「Swift 产物」分支)
- [[re-ios]] / [[re-macos]]:生态衔接(ObjC 层、App 层分析)
- [[re-format-macho]]:Mach-O 段/反射段定位工具链
- [[re-cpp-abi]]:vtable/witness table 恢复思路同源
- [[re-frida]]:运行时 hook Swift 函数(符号解码后的名称直接作 hook 点)
- [[re-analyze/analysis-contract]]:符号表按数据契约传递
常见坑与陷阱
- mangling 版本差异:现象——新版本 Swift 产物解码失败或输出乱码;原因——mangling 方案演进(
$s/$S/_T0三代);对策——用与目标编译版本同代或更新的 swift-demangle,_T0老符号新工具也能解,但新符号老工具不行 - 泛型展开符号爆炸:现象——解码输出大量
$s...Gy泛型实例;原因——泛型特化;对策——按模块/类型聚类过滤,先还原未特化原型 - witness table 无符号名:现象——分发表槽位全是裸地址;原因——协议 conformance 无命名符号;对策——结合协议方法调用点(witness method 调用处)反推槽位语义
- 闭包捕获含引用语义:现象——context 字段是引用计数对象;原因——捕获变量含类实例;对策——按 swift_retain/release 调用点确认引用字段,别当值类型读
- 纯 ObjC 误入:现象——无
$s却按 Swift 流程走;原因——产物实为 ObjC;对策——步骤 1 先确认(无$s/__swift5_*即转) - mangled 名不是普通字符串:现象——
strings/grep 截断或漏检部分符号;原因——mangled 名可含\x01-\x1f控制字符后跟指针字节(symbolic reference),不是以\0结尾的干净串;对策——符号提取用llvm-nm/readelf -s的符号表,不用strings兜底;解析器遇到控制字符要拒读指针字节 - strip 后反射段仍在但符号名没了:现象——
__swift5_proto段还在、$s符号列表为空;原因——strip 只删符号表,反射元数据(conformance/fieldmd)属数据段;对策——从反射段重建类型/协议关系,不依赖符号名 _To后缀被当普通符号:现象——foo.bar.bas(zim:)和@objc foo.bar.bas(zim:)两个符号并存,漏掉后者;原因——_To是 @objc 桥接 thunk;对策——_To与本体成对分析,ObjC 侧调用经 thunk 进 Swift 实现- 入口不是 ObjC 的 main 视角:现象——按
main函数分析发现"入口"只有薄薄一层;原因——Swift 可执行文件入口是@main/顶层代码经运行时初始化(swift_retain 大量出现于启动路径);对策——从main反汇编沿运行时调用链找到第一个用户类型的方法调用点再深入,别在初始化包装里打转 - Swift 4 老产物无反射段:现象——没有
__swift5_*段、符号又被 strip,只剩_T/_T0前缀残迹;原因——反射系统 5.0 才引入;对策——按 mangling 前缀(_TtC等)与swift_retain/swift_release运行时调用点识别 Swift 侧代码,从 ObjC 段(__objc_classlist)补类型骨架