一. 引言
受历史包袱影响,当前大厂主流 App 仍以 Objective-C (OC) 为核心,但自 Swift ABI 稳定以来,大厂对 Swift 的投入已进入增长期。在逆向工程和插件开发中,面对越来越多的 Swift 代码,掌握 Swift Hook 技术变得至关重要。
二. Swift 与 OC Hook 的本质区别
Objective-C 的方法调用基于 Runtime 消息发送机制 (objc_msgSend),这使得 Method Swizzling 变得非常简单且强大。而 Swift 为了性能,引入了更复杂的派发机制:
- 静态派发 (Static Dispatch): 编译期确定函数地址,直接内联或跳转,无法通过 Runtime 替换。常见于
final修饰的方法、struct/enum的方法以及 extension 中的默认实现。 - 动态派发 (Dynamic Dispatch):
- 基于 VTable (虚函数表): 纯 Swift 类默认使用这种方式。
- 基于 OC Runtime (消息发送): 继承自
NSObject或被@objc dynamic修饰的方法,依旧走 OC 消息转发流程。
三. 方案一:利用 OC Runtime (最推荐)
这是最简单且最稳定的方式,但前提是目标 Swift 方法必须暴露给 Objective-C Runtime。
3.1 适用场景
- 类继承自
NSObject。 - 方法或属性被
@objc或@objc dynamic修饰。
3.2 Logos 实战技巧
由于 Swift 类使用了 Name Mangling (名称修饰),类名通常不是简单的字符串(如 MyClass),而是像 _TtC5MyApp7MyClass 这种形式。在 Logos (Theos) 中,直接 Hook 往往会失败。我们可以使用 动态获取类 + 显式初始化 的技巧。
// 1. 定义 Hook 组和占位符类名
%group MySwiftHook
%hook MySwiftClass // 这里的名字可以随便取,只是个占位符
- (NSString *)displayName {
NSString *originalName = %orig;
NSLog(@"[Hook] 获取用户名: %@", originalName);
return [NSString stringWithFormat:@"[VIP] %@", originalName];
}
%end
%end
%ctor {
// 2. 动态查找 Swift 类
// Swift 类名通常格式为: ModuleName.ClassName
NSString *className = @"MyAppModule.User";
Class cls = NSClassFromString(className);
// 3. 如果找到了类,手动初始化 Hook 组,将占位符绑定到真实类上
if (cls) {
%init(MySwiftHook, MySwiftClass = cls);
} else {
NSLog(@"[Error] 未找到类: %@", className);
}
}
提示: 如何确定
className?可以使用 nm 命令查看二进制符号,或者在运行时通过 objc_copyClassNamesForImage 打印所有类名。四. 方案二:基于 Name Mangling 的符号 Hook
对于静态派发的 Swift 函数,或者 C 函数,我们可以利用 Fishhook (iOS) 或 Dobby 等 Inline Hook 框架,针对符号地址进行替换。
4.1 获取 Mangled Name
Swift 函数名在编译后会被重整。例如 func calculate(x: Int) -> Int 可能变成 $s5MyApp9calculate1xS2i_tF。
- 使用
nm -g path/to/binary | grep "functionName"查找符号。 - 使用
swift demangle还原符号含义。
4.2 Dobby Hook 示例 (伪代码)
// 声明原函数指针
int (*orig_calculate)(int);
// 新函数
int my_calculate(int x) {
return orig_calculate(x * 2); // 修改参数
}
// 注入
void* addr = DobbySymbolResolver(NULL, "$s5MyApp9calculate1xS2i_tF");
DobbyHook(addr, (void*)my_calculate, (void**)&orig_calculate);
五.实战
创建一个 Swift 语言的 App 项目测试,
写一个继承 NSObject 的类,使用 @objc dynamic 修饰变量
import Foundation
import UIKit
class User: NSObject {
@objc dynamic var name: String
@objc dynamic var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
super.init()
}
@objc dynamic func exampleName() -> String {
return name
}
@objc dynamic func exampleAge() -> Int {
return age
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// 测试调用
let user = User(name: "IosBX", age: 17)
print("用户名字: \(user.exampleName())")
print("年龄检查: \(user.exampleAge())")
}
}
用 Theos 创建一个 Tweak,
#import <Foundation/Foundation.h>
%group SwiftHook
%hook User
- (NSString *)exampleName {
NSString *originalName = %orig;
return [NSString stringWithFormat:@"[Hacked] %@", originalName];
}
- (NSInteger)exampleAge {
NSInteger originalAge = %orig;
return 999;
}
%end
%end
%ctor {
// 动态查找 Swift 类
// 格式通常为: ModuleName.ClassName
NSString *className = @"SwiftApp.User";
Class cls = NSClassFromString(className);
if (cls) {
%init(SwiftHook, User = cls);
}
}




文章评论