Swift 逆向
SkillDev toolsSwift 二进制逆向:mangling 解码、协议 witness table、闭包捕获、ObjC 互操作。 触发词:Swift逆向、swiftc、witness table、swift demangle、闭包捕获、Swift 产物。
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Swift 逆向 skill
What this skill tells your AI
The instructions your AI receives, as published by dslsdzc/rev-skills in .claude/skills/re-swift/SKILL.md and read by ahel’s review.
何时使用 / 何时不用
- 用: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)补类型骨架
Signals
- GitHub stars
- 57
- Forks
- 8
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
re-swift- Source
- github.com/dslsdzc/rev-skills