概览
承接上一篇博文:
- Swift 从获取所有 NSObject 对象聊起:ObjC、汇编语言以及底层方法调用链(二)
我们在其中讨论了如何使用第三方强大通用的钩子库 SwiftHook 来协助我们完成 NSObject 构造器 init 的 SWIZZ 操作。我们还讨论了为什么用 print 打印对象信息时会发生崩溃,以及如何巧妙的解决它。
而在本篇博文中我们将来聊聊如何完全靠自己动手“丰衣足食”,来实现 SwiftHook 里相似的功能。
在本篇博文中,您将学到如下内容:
- 概览
- 5. 完全自己撸码真的“难如登天”吗?
- 6 需要攻克的两个难关
- 7. 让 ARC 不再“指手画脚”!
- 总结
而在下一篇博文中,我们将解决最后一个难题,从而离“钩子”大冒险的终点更加的接近啦!
那么还等什么呢?让我们继续探幽未完成的冒险小径吧!
Let‘s dive in!!!😉
5. 完全自己撸码真的“难如登天”吗?
虽然我们还沉浸在 SwiftHook 完美 SWIZZ 的喜悦之中,但这毕竟是借助了第三方的力量。
我们能否彻底退出“复仇者联盟”,而完全靠自己撸码来尽可能实现 SwiftHook 的功能呢?
答案是:Yes and No!
是的,我们可以不通过 SwiftHook 来完成非常底层的系统调用,因为它是一个面面俱到、非常完善的钩子库。正是由于它的大而全导致其实现相对复杂,而我们在这里只需要挂载 NSObject.init 这一种情况下的钩子,所以我们可以直接无视其它各种“荆棘”的分支情况,集中全部精力做到极致简单。
不过,即使是这样我们仍然不能 100% 实现 SwiftHook 的功能,因为 FFI 调用对底层的稳定性来说太关键了。我们只能借助一些 Hack 机制来“无限逼近”SwiftHook 的结果。但所幸的是,这对于我们的使用场景来说已经足够了,更何况在“折腾让人快乐”的路途中我们可以学到良多,这就足矣了!
我们的战略目标是:不打算用任何第三方库来实现 NSObject.init 的钩子功能,包括 SwiftHook 和 FFI。
明确了目的,下面我们就来看看为什么之前那个“天真”的实现会让我们“死得很惨”。
6 需要攻克的两个难关
为了便于大家回忆,这里贴出之前的 Hook 代码:
class func tryHookNSObjectInit() {
let oldInitSel = #selector<