iOS 逆向

iOS 越狱检测机制与绕过原理全解析

2025-07-12 wangjun 17 min read
0x

为什么 App 要检测越狱?

越狱后用户获得 root 权限,可以注入插件、篡改内存、绕过内购。对金融、风控、游戏类 App 而言,越狱设备是黑产的高发区,因此必须能识别出"环境不可信"并采取降级策略(禁用功能、强制退出、上报风控)。

常见的检测手段

1. 文件路径检测

越狱环境会在文件系统留下特征痕迹,最经典的检测方式就是检查这些路径是否存在:

NSArray *paths = @[
  @"/Applications/Cydia.app",
  @"/Library/MobileSubstrate/MobileSubstrate.dylib",
  @"/usr/sbin/sshd",
  @"/bin/bash",
  @"/var/cache/apt",
  @"/etc/apt"];

for (NSString *p in paths) {
  if ([[NSFileManager defaultManager] fileExistsAtPath:p]) {
    return YES; // 检测到越狱
  }
}

2. 动态库注入检测

越狱插件通过 DYLD_INSERT_LIBRARIES 或 MobileSubstrate 注入,App 可以遍历已加载的动态库:

BOOL hasSubstrate = NO;
uint32_t count = _dyld_image_count();
for (uint32_t i = 0; i < count; i++) {
  const char *name = _dyld_get_image_name(i);
  if (strstr(name, "MobileSubstrate") ||
      strstr(name, "Substrate")) {
    hasSubstrate = YES;
  }
}

3. 行为与沙盒检测

  • fork 检测:越狱环境下 fork() 可以成功执行,正常沙盒会返回 -1
  • 沙盒逃逸:尝试向沙盒外(如 /var/test)写入文件,成功即越狱
  • URL Scheme:尝试打开 cydia:// 看是否可用
  • 系统调用:调用 sysctl 读取内核标志位

绕过思路:对症下药

检测的本质是"查询环境",绕过就是让查询返回"正常"的结果。最直接的方式是 Hook 掉检测函数:

%hook NSFileManager

- (BOOL)fileExistsAtPath:(NSString *)path {
  NSArray *blacklist = @[@"/Applications/Cydia.app",
                          @"/bin/bash", @"/usr/sbin/sshd"];
  if ([blacklist containsObject:path]) {
    return NO; // 对特征路径一律说不存在
  }
  return %orig;
}

%end

更隐蔽的绕过会 Hook _dyld_image_count_dyld_get_image_name,在遍历结果中过滤掉注入库。

反绕过:检测方的升级

绕过手段普及后,防御方也开始反制:

  • 关键检测下沉到 C 层:把检测函数写成 C 函数甚至内联汇编,避开 OC 的 Runtime Hook
  • 服务端校验:客户端只上报特征,由服务端综合判断,防止本地全被 Hook
  • 完整性校验:对自身 Mach-O 做哈希比对,发现被修改即退出
  • 反调试:检测 ptrace 与调试器附加(sysctl P_TRACED

写在最后

越狱检测与绕过是一场持续的军备竞赛。无论攻守,都请牢记:逆向分析仅限自有 App 或已授权的安全研究,未经授权的破解、绕过风控均属违法行为。

检测与绕过之间没有银弹,只有对系统机制理解深度的较量。