如何使用Frida拦截Swift类的构造函数init并解决相关报错
解决方案
问题根因
你之前的写法错误核心原因是两点:
- Swift类存在命名 mangling 规则,构造函数存在多重重载,无法直接通过
.init属性直接获取方法引用 - 未使用带模块前缀的完整类名获取目标类,直接调用
.init会因为找不到对应方法抛出参数缺失、属性未定义等错误
操作步骤
1. 确认目标类的完整名称
Swift类的完整标识格式为[主模块名].[类名],主模块名默认和应用名一致(比如你的应用包是com.example.myapp,模块名一般为MyApp),获取类的正确写法为:
const targetClass = Swift.classes['MyApp.hooked_class']
2. 遍历类的所有方法识别构造函数
运行以下脚本打印目标类的所有方法信息,快速定位init构造函数:
targetClass.$methods.forEach((method, index) => { console.log(`[${index}] 地址: ${method.address}, 方法名: ${method.name}, 签名: ${method.typeSignature}`) })
Swift的构造函数命名会明确包含init前缀,部分带参数的构造函数会显示完整参数列表(比如init(identifier:count:)),很容易识别。
3. 两种方式Hook构造函数
方式1:通过方法索引/方法对象Hook
如果你已经通过上述打印结果确认索引为N的方法是目标init,直接传入方法对象即可:
const targetInit = targetClass.$methods[N] Swift.Interceptor.attach(targetInit, { onEnter(args) { // args[0] 为当前实例self,args[1]为selector,后续为自定义入参 console.log('构造函数触发,实例地址:', args[0]) }, onLeave(retVal) { console.log('构造完成,返回实例:', retVal) } })
方式2:通过地址直接Hook
如果你已经确认某内存地址对应init方法,也可以直接传入指针对象:
Swift.Interceptor.attach(ptr('0x1008e37b8'), { onEnter(args) { console.log('通过地址Hook到构造函数') } })
新手快速定位构造函数技巧
如果无法从方法名判断哪个是init,可以临时Hook所有方法,触发类实例化时看调用日志即可:
targetClass.$methods.forEach(method => { Swift.Interceptor.attach(method, { onEnter() { console.log('触发方法:', method.name, '地址:', method.address) } }) })
运行应用触发目标类的实例化操作,日志中对应调用的方法即为构造函数。
常见错误解释
- 调用
Swift.classes.hooked_class.init报missing argument:未找到对应init方法,bridge需要明确指定重载的构造函数 - 调用
.init()报not a function:init属性本身不是可调用对象,需要通过$methods或$getMethod获取合法方法引用 - 调用
.init.implementation报undefined:init属性未定义,说明你直接通过类名点init的方式根本没有拿到对应的构造函数对象
内容的提问来源于stack exchange,提问作者systemdev
相关产品推荐
相关产品推荐

