现象:解密的速度极其缓慢,而且经常解密很短一段时间后就卡死
原因:GateKeeper对每个文件都进行了扫描,这导致:
- 规则里有许多yara扫描,本身就会消耗资源
- GateKeeper将结果存到了
/var/db/SystemPolicyConfiguration/ExecPolicy这个sqlite db中,长期累积后记录数量能达到数千万,导致插入、查询都非常缓慢,
理解GateKeeper的架构
GateKeeper由几部分组成:
- syspolicyd:负责调度XProtectService等功能,并执行最终的决策,决定是否允许程序启动
- XProtectService:负责进行具体的yara scan
GateKeeper有几个关键点:
- syspolicyd注册了相应的接口,可以通过RPC来增加exec policy的记录
- syspolicyd会将判断的结果存入
/var/db/SystemPolicyConfiguration/ExecPolicy的policy_cache_by_path_meta 和 policy_cache_meta 表中
- syspolicyd判定时,如果发现
ExecPolicy中已经完成过yara扫描,那么会直接从库中取出,而不是每次重新扫描。判定时会首先查询policy_scan_cache,如果没查到再继续查policy_scan_cache_by_path。前者是根据vnode id、size、mod time索引,后者则是根据fstype、mountpoint、path、size、mod time
- XProtectService的规则来自于
/Library/Apple/System/Library/CoreServices/XProtect.bundle和/var/db/SystemPolicyConfiguration/XProtect.bundle中
GateKeeper有几种拦截原因,我们在iOS中碰到的主要是这两种:
- 应用程序中有病毒代码(policy result = 8):例如PayZApp
- TeamID被拉黑(policy result = 10):例如com.pps.test
尝试攻克GateKeeper中的各种失败
尝试1:xattr -d com.apple.quarantine
这是从网上下程序时可以使用的命令,但是实际上用完并没有效果
尝试2:提前注册与XprotectService同名的服务
xnu的daemon都是按照包名来划分domain的,很好的防范了水坑攻击
尝试3:RPC注入,配置override,相当于在设置里手动点击允许
并没有卵用,还是被ban
#include <stdio.h> #import <Foundation/Foundation.h> #import "SPExecutionPolicy.h" int main(int argc, char *argv[], char *envp[]) { @autoreleasepool { printf("Hello world!\n"); SPExecutionPolicy *execPolicy = [[SPExecutionPolicy alloc] init]; NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:argv[1]]]; NSError *error = nil; /*[execPolicy addBlockedSoftwareOverride:url error:&error]; if (!!error) { NSLog(@"Error in addBlockedSoftwareOverride: %@", error); return 1; } NSLog(@"add override OK!");*/ [execPolicy setBlockedSoftwareOverride:url isEnabled:NO error:&error]; if (!!error) { NSLog(@"Error in setBlockedSoftwareOverride: %@", error); return 1; } NSLog(@"set override OK!"); return 0; } }
最终的邪修道路
我们用的11.2系统完全可以用CoreTrust bypass洞,所以肯定是从文件下手。
首先是把syspolicyd的entitlement整个偷一遍,这个时候我们就已经有直接读写sip的权限了。我直接签了一个busybox、一个sqlite3。
当扫描结果不对时,malware_result会不为0,然后自然出发相应的阻断逻辑。所以我们直接把malware_result都改成0,完美解决。(注意不能删库,要不然重启之后会需要等很久校验Xcode签名)
update policy_scan_cache_by_path set policy_match = 8, malware_result = 0 where malware_result != 0
接下来就是个大难题了, team id拉黑的情况完全绕不开,因为这种验证太快了,所以苹果完全不参考数据库的结果,而且blockedOverride也没有用。
考虑从源头的规则下手,
/var/db/SystemPolicyConfiguration/XProtect.bundle 里面存的有teamid黑名单列表,所以尝试了:- 尝试直接删掉, 发现会自动出现
- 尝试修改里面的内容,发现并不能应用上去
- 最后逆向发现XProtect.bundle有签名,通过Sec*** API验证通过后才会被架子啊
这些方法不成立的原因主要还是一方面bundle有签名,另一方面系统里面还内置了一个不可变的
/Library/Apple/System/Library/CoreServices/XProtect.bundle,很不幸,2022年的时候我们的目标应用已经上了黑名单。。费劲九牛二虎之力还是没办法, 最后想到了个阴招。从mount和其他工具偷了许多entitlement,实现能在/Library目录下面进行mount了。然后把XProtect.bundle mount成了一个大小为1m的空文件夹,整个XProtect就失效了,同时程序还能正常加载。配合前面的数据库大法实现了完全解密全部的文件。