修复 macOS 应用去除签名后的沙盒路径

自从做了两个Tweak:WeChatTweak-macOSQQTweak-macOS,发现了都存在一个共同问题:由于以上两个应用都采用了 macOS 的沙盒机制,同时插入动态库时签名被移除,导致了沙盒失效,拖延症的我终于在国庆期间修复,并记录一下过程。

0x00 举个例子

以下应用在安装完 Tweak 之后,会导致沙盒失效,因此会导致聊天记录等文件无法加载,同时文件路径会出现错乱。囧rz……

  1. WeChat
    • 无法加载历史聊天记录等
    • ~/Documents 目录下出现 MMappedKV 文件夹。参考 #19
    • ~/Documents 目录下出现 JietuSDKStat.plist。参考 #21
    • ~/Documents 目录下出现 .rdq 文件夹。
  2. QQ
    • 无法加载历史聊天记录等
    • ~/Documents 目录面目全非

NoSandbox

0x01 沙盒

沙盒的大概意思:

AboutSandbox

有兴趣的可以查看 Apple 官方文档:About App Sandbox

那么对于 QQ 原有的沙盒路径应该是这样的:

Sandbox

可见沙盒其实就是在 ~/Library/Containers/{bundleid}/Data 目录下拥有和 ~ 目录相同的目录结构的一个文件夹,其实就是为了限制应用的访问权限,同时可以看到有很多软链接的目录或文件。其中主要的就是 DocumentsLibrary 目录了。

0x02 修复方案

很简单,找到返回路径的相关方法进行替换即可,通过 Hopper Disassembler 对以上两个应用进行静态分析搜索关键字 pathlocation 还有文件夹的名字等,中间过程略……

通过观察找到的所有与路径相关的方法都使用了同一个函数,最终定位出方法 NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde)

0x04 踩坑

然而发现 NSSearchPathForDirectoriesInDomains 这是一个 Global Function,并不是 Objective-C 中的一些类方法对象方法,因此需要 Hook 这个方法的话 Method Swizzling 就不起作用了。

因此本文将介绍另一款神器:fishhook,是由 Facebook 开源的动态修改 C 语言函数实现,专治各种疑难 Hook 的框架,详细的介绍和源码还是自己去看 GitHub 吧。

参考资料:动态修改 C 语言函数的实现

0x05 编写 Tweak

声明一个与原函数签名相同的函数指针和新函数:

1
2
3
4
5
6
7
// 原始方法
static NSArray<NSString *> *(*original_NSSearchPathForDirectoriesInDomains)(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);
// 替换方法
NSArray<NSString *> *tweak_NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde) {
}
// 这里将返回应用沙盒路径
}
1
2
3
4
5
6
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 的安装与卸载等操作都不会影响到沙盒路径访问的问题了。