百趣云 百趣云的博客

iOS 越狱检测的原理与绕过:tweak 开发视角

越狱检测在检测什么

iOS App(尤其是金融、政务类)启动时普遍做越狱检测,检测到就闪退或限制功能。检测点分四类:

1. 文件系统特征

越狱后多出来的文件是第一批路标:

NSArray *paths = @[@"/Applications/Cydia.app",
                   @"/usr/sbin/sshd",
                   @"/usr/bin/ssh",
                   @"/etc/apt",
                   @"/Library/MobileSubstrate/MobileSubstrate.dylib",
                   @"/var/lib/cydia"];
for (NSString *p in paths) {
    if ([[NSFileManager defaultManager] fileExistsAtPath:p]) {
        // 判定越狱
    }
}

2. 沙箱完整性:越狱机可以读写沙箱外路径,App 尝试往 /private/ 写测试文件,成功即越狱。

3. URL Scheme[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]],能打开 Cydia 协议就是越狱机。

4. 动态库注入_dyld_get_image_name 遍历加载的 dylib,出现 MobileSubstrateSubstrateLoaderTweakInject 等注入框架特征即中招。

绕过:tweak 开发实战

在越狱机上写 tweak 对抗检测,用 Logos 语法(Theos 工程):

// Tweak.x
%hook NSFileManager
- (BOOL)fileExistsAtPath:(NSString *)path {
    NSArray *jailbreakPaths = @[@"/Applications/Cydia.app", @"/usr/sbin/sshd", @"/etc/apt"];
    if ([jailbreakPaths containsObject:path]) {
        return NO;   // 对越狱特征文件谎报"不存在"
    }
    return %orig;
}
%end

%hook UIApplication
- (BOOL)canOpenURL:(NSURL *)url {
    if ([[url absoluteString] hasPrefix:@"cydia://"]) return NO;
    return %orig;
}
%end

编译安装:

# Theos 工程
make package install THEOS_DEVICE_IP=192.168.1.x

精髓一:hook 要覆盖所有读取通道

只 hook fileExistsAtPath 不够——检测代码可能用 C 层的 stat()access()fopen() 直接查文件。完整绕过要同时 hook:

// C 层 hook 用 MSHookFunction(substrate)或 fishhook
int (*orig_stat)(const char *path, struct stat *buf);
int fake_stat(const char *path, struct stat *buf) {
    if (strstr(path, "Cydia") || strstr(path, "apt")) return -1;
    return orig_stat(path, buf);
}
// MSHookFunction(stat, fake_stat, &orig_stat);

审计检测代码时用 Hopper/IDA 搜全部文件 API,列清单逐个 hook,漏一个就前功尽弃。

精髓二:dyld 检测的对抗

遍历 dylib 的检测最难缠——substrate 框架本身就在 dylib 列表里。对抗思路:

%hookf(const char *, _dyld_get_image_name, uint32_t index) {
    const char *name = %orig(index);
    if (name && (strstr(name, "Substrate") || strstr(name, "Tweak"))) {
        return "/usr/lib/system/libsystem_c.dylib";  // 伪装成系统库
    }
    return name;
}

更彻底的是用 ElleKit/roothide 这类新型注入框架(dylib 路径不含特征词),或改用基于 DYLD_INSERT_LIBRARIES 之外的无文件注入方案。

精髓三:先逆向检测逻辑再写绕过

别盲目 hook——先用 Hopper 反编译 App,搜 jailbreakcydiaapt 等字符串,找到检测函数,看清它:

  • 检测哪些点(清单)
  • 检测到后做什么(闪退?上报?静默标记?)

静默标记型最危险:检测到越狱不闪退,但把你的设备标记上报风控,后续请求全部进高风险队列。绕过的验证标准不是"App 能跑",而是"对比越狱/非越狱设备的请求参数无差异"。

总结

  1. 越狱检测四类点:文件特征、沙箱完整性、URL Scheme、dylib 注入
  2. tweak 绕过要覆盖 OC 层和 C 层所有文件 API
  3. dyld 检测用 hookf 伪装库名,或换无特征注入框架
  4. 先逆向检测逻辑列清单,静默标记型检测最危险

交流微信:run1255

By 百趣云 阅读量:4 On