Jailbreak Detection — 一套检测iOS设备上是否存在越狱并阻止应用程序在已解除限制的环境中启动的机制。越狱允许访问沙盒外的文件系统,从而可以安装修改过的库和拦截系统调用。根据Apple Security Documentation (2024),越狱设备不符合安全启动模型Secure Boot。Jailbreak Detection结合了文件指示器检查、运行时调用分析和沙盒签名完整性控制。
要点
Jailbreak Detection — 识别已解除操作系统限制的iOS设备的过程。越狱修改iOS内核,禁用代码签名,提供对完整文件系统的访问,并允许加载未授权的库。对于在此类设备上运行的应用程序,执行环境的完整性无法保证:任何进程都可以读取应用程序内存,通过将自身证书安装到系统存储中拦截SSL/TLS流量,并通过Cydia Substrate或Substitute注入代码。
iOS上的金融应用程序必须根据PCI DSS标准的要求实施Jailbreak Detection——为了获得认证,应用程序必须证明其未在受感染设备上运行。OWASP Mobile Security(2024)将缺少Jailbreak Detection归类为M8漏洞。对于App Store应用程序,Apple不禁止在越狱设备上阻止功能,但建议结合客户端和服务器端检查,不要仅依赖可能被修改的客户端代码。
由于沙盒模型,iOS中的Jailbreak Detection架构比Android中的Root Detection更复杂。在Android中,应用程序可以读取/proc来分析系统。iOS沙盒阻止对大多数系统指示器的直接访问。开发者不得不使用绕过技术,例如通过canAccessFile API检查禁止区域中文件的可访问性,或通过fork()启动子进程并检查退出代码。现代检查基于尝试执行仅在越狱时可行的操作并分析结果。
最简单且历史上第一种方法——检查仅在越狱设备上安装的文件和应用程序是否存在。尽管简单,文件检查仍然是基本的保护层,因为绕过它们需要用户采取主动行动。
在越狱设备上存在Cydia、Sileo、Zebra或Installer应用程序。通过NSFileManager检查它们是否存在:[[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"]。类似地检查unc0ver、checkra1n、Taurine和Chimera的包。这些检查可通过拦截NSFileManager调用的HideJB插件绕过。
越狱安装stock iOS中不可用的UNIX工具:apt、dpkg、ssh、rsync、sftp、dd、readlink等。检查/usr/bin/ssh、/bin/bash、/bin/sh和/usr/libexec/sftp-server是否存在。成功检测到任何这些文件时,越狱概率很高。对于iOS 13–17,还建议检查/var/jb——unc0ver和Taurine的bootstrap根目录是否存在。
MobileSubstrate(CydiaSubstrate.dylib)和Substitute——用于向进程注入代码的库。通过使用RTLD_NOLOAD标志的dlopen()检查它们是否存在。如果库已加载到地址空间中——进程在越狱环境中运行。这是一个更可靠的检查,因为HideJB无法卸载已经加载到进程中的库。
- (BOOL)isJailbrokenByFiles {
NSArray *paths = @[
@"/Applications/Cydia.app",
@"/Applications/Sileo.app",
@"/Applications/Zebra.app",
@"/usr/bin/ssh",
@"/bin/bash",
@"/var/jb",
@"/etc/apt"
];
for (NSString *path in paths) {
if ([[NSFileManager defaultManager]
fileExistsAtPath:path]) {
return YES;
}
}
return NO;
}
- (BOOL)isSubstrateLoaded {
void *handle = dlopen(
"/Library/MobileSubstrate/MobileSubstrate.dylib",
RTLD_NOLOAD | RTLD_LAZY
);
if (handle) {
dlclose(handle);
return YES;
}
return NO;
}
动态检查执行iOS沙盒中禁止的操作并分析结果。如果操作未被阻止——设备很可能已越狱。
在stock iOS中,fork()调用返回-1并设置errno = EPERM。在越狱设备上,fork()可以执行,因为沙盒限制已被解除。此检查可靠,但在某些iOS版本上可能导致误报。fork()也可以替换为posix_spawn()来检查启动子进程的可能性。
尝试读取禁止区域中的文件:/etc/master.passwd、/var/log/system.log、/private/var/cache。在stock iOS中,这些读取返回错误。如果应用程序成功读取这些文件——沙盒已禁用。此外,检查写入/private/的可能性——在沙盒中,所有系统分区对普通应用程序以只读方式挂载。
越狱修改系统库,包括dyld共享缓存。检查系统框架或单个符号的哈希值可以发现修改。对于iOS 14+,通过读取sysctl kern.version检查内核地址空间中是否存在jit_region_create符号或其他Fugu14/checkra1n工作迹象。
- (BOOL)isJailbrokenByRuntime {
// 检查fork()
int pid = fork();
if (pid == 0) {
exit(0);
}
if (pid > 0) {
waitpid(pid, NULL, 0);
return YES;
}
// 检查对系统文件的访问
FILE *f = fopen("/etc/master.passwd", "r");
if (f) {
fclose(f);
return YES;
}
// 检查sysctl kern.version
size_t size = 0;
sysctlbyname("kern.version", NULL, &size, NULL, 0);
if (size > 0) {
char *version = malloc(size);
sysctlbyname("kern.version", version, &size, NULL, 0);
NSString *str = [NSString stringWithUTF8String:version];
free(version);
if ([str containsString:"pwned"]) {
return YES;
}
}
return NO;
}
Swift代码很容易被反汇编并通过Substrate绕过。使用直接调用libobjc和C系统函数的Objective-C原生实现使检查对绕过具有显著更强的抵抗力。
来自libc的stat()调用无法在Objective-C级别被拦截。拦截NSFileManager方法的HideJB插件不影响stat()。使用stat()的原生检查即使在安装了HideJB模块的设备上也能检测到文件指示器。将stat()用于文件和将dlopen()与RTLD_NOLOAD用于库相结合,提供了两个不重叠的检测通道。
原生函数SecStaticCodeCheckValidity检查应用程序代码签名是否符合Apple证书。在越狱设备上,此检查可通过内核补丁被替换。为避免替换,应从原生代码通过dlopen()从Security.framework调用执行检查,而不是通过Swift Bridge。
#import <sys/stat.h>
#import <dlfcn.h>
- (BOOL)nativeCheckForJailbreak {
// stat()绕过NSFileManager钩子
struct stat st;
if (stat("/Applications/Cydia.app", &st) == 0) {
return YES;
}
// 使用dlopen检查Substrate而不加载
void *substrate = dlopen(
"/Library/MobileSubstrate/MobileSubstrate.dylib",
RTLD_NOLOAD
);
if (substrate) {
dlclose(substrate);
return YES;
}
return NO;
}
理解绕过技术对于建立持久的保护是必要的。现代绕过工具正在积极发展,静态的检查集在几个月内就会变得无效。
HideJB——拦截NSFileManager、stat()、dlopen()和fork()调用并替换返回值的插件。HideJB在Cydia Substrate级别工作,因此拦截Objective-C和C函数。用于iOS 15–16的HideJB版本(Shadow)使用内核级钩子方法。对策:在单独的进程中执行检查,通过IPC传输结果,从而打破钩子链。
Choicy允许为特定进程禁用Substrate。用户只需禁用受保护应用程序的注入——所有库检查都返回false。Liberty Lite——全面的绕过工具,覆盖大多数流行的保护库检查。对策:通过DeviceCheck和App Attest进行服务器验证——在服务器上检查设备是否具有有效的Apple证书,该证书在越狱设备上无法伪造。
像Fugu14和KFD这样的内核漏洞利用程序在内核空间执行代码,从而可以在应用程序看到系统调用之前拦截它们。在这个级别上,stat()和fork()检查变得无效。唯一可靠的对策——服务器认证,确认设备已通过Apple Attestation程序。该协议基于Secure Enclave内的加密密钥,即使在内核级漏洞利用时也无法读取。
要建立有效的Jailbreak Detection,必须了解哪些iOS安全机制在越狱时被禁用。
iOS通过签名检查序列启动:Boot ROM → iBoot → iOS Kernel。如果越狱使用bootrom漏洞(checkra1n),整个Secure Boot Chain被破坏——应用程序级别的检查毫无用处。如果使用纯软件漏洞(unc0ver、Taurine、Fugu14),启动链未被破坏,像App Attest这样的Apple服务仍然可信。
从iOS 10开始,Apple引入了KPP——一种每200毫秒重新检查内核完整性的硬件保护。所有现代越狱(iOS 14–17)都通过PAC或APRR绕过KTRR,但KPP会以修改过的sysctl系统表的形式留下痕迹。检查kern.version中是否存在pwned、prod或具有非标准版本的xnu字符串可以检测到内核补丁的存在。
iOS沙盒使用entitlements在TrustedBSD级别工作。越狱将沙盒配置文件替换为allow-all。应用程序可以通过尝试读取其Documents目录之外的任何文件来检查沙盒。如果成功——沙盒已被修改。沙盒完整性——少数几个无需内核级漏洞利用就无法伪造的指示器之一,因为权限检查在内核中执行,然后才能被拦截。
常见问题
Android的Root Detection检查su二进制文件和Magisk的存在。Jailbreak Detection for iOS寻找Cydia、Sileo、MobileSubstrate,检查fork()的可能性并读取系统文件。iOS沙盒架构比Android更严格,因此iOS检查更多地依赖于尝试执行被禁止的操作,而不是读取系统指示器。
是的,对于iOS 16–17,Dopamine、palera1n和checkra1n越狱仍然有效。Jailbreak Detection有效,但需要针对新工具更新检查。在iOS 17中,Apple加强了沙盒,许多旧检查(例如fork())由于XNU中的更改而不再可靠
最简单的方法是HideJB或Shadow,它们在库级别拦截检查。对于更复杂的保护,使用Frida或Choicy禁用特定应用程序的注入。服务器认证(App Attest)只能通过替换Secure Enclave硬件的内核级漏洞利用来绕过,这实际上是不可行的。
越狱设备上的任何应用程序都可能遭受:通过修改受信任存储区拦截SSL流量,通过访问文件系统读取钥匙串,通过Substrate进行代码注入并拦截令牌处理方法,转储进程内存以获取加密密钥。
App Attest是Apple用于检查应用程序和设备完整性的服务。启动时,应用程序从Apple服务器接收attestation challenge,使用来自Secure Enclave的私钥签名并发送到自己的服务器。如果设备已越狱,Secure Enclave会响应attestation failure,从而阻止对受保护功能的访问。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。