修复 macOS 应用去除签名后的沙盒路径
自从做了两个Tweak:WeChatTweak-macOS 和 QQTweak-macOS,发现了都存在一个共同问题:由于以上两个应用都采用了 macOS 的沙盒机制,同时插入动态库时签名被移除,导致了沙盒失效,拖延症的我终于在国庆期间修复,并记录一下过程。
0x00 举个例子
以下应用在安装完 Tweak 之后,会导致沙盒失效,因此会导致聊天记录等文件无法加载,同时文件路径会出现错乱。囧rz……
- QQ
- 无法加载历史聊天记录等
~/Documents
目录面目全非
0x01 沙盒
沙盒的大概意思:
有兴趣的可以查看 Apple 官方文档:About App Sandbox。
那么对于 QQ 原有的沙盒路径应该是这样的:
可见沙盒其实就是在 ~/Library/Containers/{bundleid}/Data
目录下拥有和 ~
目录相同的目录结构的一个文件夹,其实就是为了限制应用的访问权限,同时可以看到有很多软链接的目录或文件。其中主要的就是 Documents
和 Library
目录了。
0x02 修复方案
很简单,找到返回路径的相关方法进行替换即可,通过 Hopper Disassembler 对以上两个应用进行静态分析搜索关键字 path
、location
还有文件夹的名字等,中间过程略……
通过观察找到的所有与路径相关的方法都使用了同一个函数,最终定位出方法 NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde)
。
0x04 踩坑
然而发现 NSSearchPathForDirectoriesInDomains
这是一个 Global Function,并不是 Objective-C 中的一些类方法对象方法,因此需要 Hook 这个方法的话 Method Swizzling 就不起作用了。
因此本文将介绍另一款神器:fishhook,是由 Facebook 开源的动态修改 C 语言函数实现,专治各种疑难 Hook 的框架,详细的介绍和源码还是自己去看 GitHub 吧。
参考资料:动态修改 C 语言函数的实现
0x05 编写 Tweak
声明一个与原函数签名相同的函数指针和新函数:
// 原始方法
static NSArray<NSString *> *(*original_NSSearchPathForDirectoriesInDomains)(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);
// 替换方法
NSArray<NSString *> *tweak_NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde) {
}
// 这里将返回应用沙盒路径
}
static void __attribute__((constructor)) tweak(void) {
// 将 rebindin 结构体包装成数组,对原符号 open 进行重绑定,1 为数组大小
rebind_symbols((struct rebinding[1]) {
{ "NSSearchPathForDirectoriesInDomains", tweak_NSSearchPathForDirectoriesInDomains, (void *)&original_NSSearchPathForDirectoriesInDomains }
}, 1);
}
⚠️注意:通过 DYLD_INSERT_LIBRARIES
命令进行调试的话,应用签名并没有受到影响,因此沙盒是正常的。可以通过命令 codesign --remove-signature
来去除签名之后进行调试。
0x06 最终效果
当然是沙盒路径访问正常了,通过 App Store 更新应用、Tweak 的安装与卸载等操作都不会影响到沙盒路径访问的问题了。