越狱检测
关于越狱
对于设备是否越狱的检测,看了几篇文章(文章见:文章1,文章2)以及《黑客攻防技术宝典》中对越狱的片段,结合文章的总结(如有错误或想法,望交流指导)
- 设备越狱,如果是非硬件方面的漏洞,苹果公司了解到存在于硬件中的漏洞时可以通过简单的软件升级去修复这些漏洞。如果是硬件方面,那么必须要下一设备硬件发布才能解决。
- 因此对于越狱的判断,想做到完全检测比较难。原因有几点:
- 苹果公司会根据新的漏洞作出新的应对措施,而导致越狱的漏洞攻击程序后续更改,虽然通常不过是重命名或移动根文件系统中的某些文件;
- 对于越狱检测,很大程度上都还是针对某些目录下某个文件名字是否换了或者文件被替换了等等去检测;
- 用户的版本有不同的分布;
- 不同系统/不同设备的测试条件问题;
- 用户可能安装越狱检测绕过插件(xCon)
关于检测
已有的研究很少,且研究的iOS版本较老,因此在测试时会出现检测结果不一致的情况。所以,对于越狱研究更多的可以集中在尽可能降低检测的差错率。(这里的差错率应该在这样理解:非越狱设备不能被检测为越狱设备;越狱设备被检测为非越狱设备的概率尽可能降低)。可以在不影响非越狱设备的情况下,考虑方法可能被hook的情况采用多重检测。
- 不要用NSFileManager,这是最容易被hook掉的。
- 检测方法中所用到的函数尽可能用底层的C,如文件检测用stat函数(iPod7.0,越狱机检测越狱常见的会安装的文件只能检测到此步骤,下面的检测不出来)
- 再进一步,就是检测stat是否出自系统库
- 再进一步,就是检测链接动态库(尽量不要,appStore可能审核不过)
- 再进一步,检测程序运行的环境变量
- 检测过程中,越低级检测越狱到即可认定越狱,后续的检测只是考虑越狱攻击的深度,可能考虑了更多细节
关于代码实现
- (BOOL)mgjpf_isJailbroken
{
//以下检测的过程是越往下,越狱越高级
// /Applications/Cydia.app, /privte/var/stash
BOOL jailbroken = NO;
NSString *cydiaPath = @"/Applications/Cydia.app";
NSString *aptPath = @"/private/var/lib/apt/";
if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
jailbroken = YES;
}
if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
jailbroken = YES;
}
//可能存在hook了NSFileManager方法,此处用底层C stat去检测
struct stat stat_info;
if (0 == stat("/Library/MobileSubstrate/MobileSubstrate.dylib", &stat_info)) {
jailbroken = YES;
}
if (0 == stat("/Applications/Cydia.app", &stat_info)) {
jailbroken = YES;
}
if (0 == stat("/var/lib/cydia/", &stat_info)) {
jailbroken = YES;
}
if (0 == stat("/var/cache/apt", &stat_info)) {
jailbroken = YES;
}
// /Library/MobileSubstrate/MobileSubstrate.dylib 最重要的越狱文件,几乎所有的越狱机都会安装MobileSubstrate
// /Applications/Cydia.app/ /var/lib/cydia/绝大多数越狱机都会安装
// /var/cache/apt /var/lib/apt /etc/apt
// /bin/bash /bin/sh
// /usr/sbin/sshd /usr/libexec/ssh-keysign /etc/ssh/sshd_config
//可能存在stat也被hook了,可以看stat是不是出自系统库,有没有被攻击者换掉
//这种情况出现的可能性很小
int ret;
Dl_info dylib_info;
int (*func_stat)(const char *,struct stat *) = stat;
if ((ret = dladdr(func_stat, &dylib_info))) {
NSLog(@"lib:%s",dylib_info.dli_fname); //如果不是系统库,肯定被攻击了
if (strcmp(dylib_info.dli_fname, "/usr/lib/system/libsystem_kernel.dylib")) { //不相等,肯定被攻击了,相等为0
jailbroken = YES;
}
}
//还可以检测链接动态库,看下是否被链接了异常动态库,但是此方法存在appStore审核不通过的情况,这里不作罗列
//通常,越狱机的输出结果会包含字符串: Library/MobileSubstrate/MobileSubstrate.dylib——之所以用检测链接动态库的方法,是可能存在前面的方法被hook的情况。这个字符串,前面的stat已经做了
//如果攻击者给MobileSubstrate改名,但是原理都是通过DYLD_INSERT_LIBRARIES注入动态库
//那么可以,检测当前程序运行的环境变量
char *env = getenv("DYLD_INSERT_LIBRARIES");
if (env != NULL) {
jailbroken = YES;
}
return jailbroken;
}
上面的代码为测试代码,实际应用应该任何一步检测到已越狱,就可直接返回YES,不需去进行下面的判断,BOOL的判断也可能被hook。
(iPod7.0,越狱机检测越狱常见的会安装的文件能在stat步骤检测到越狱)
如果错误,欢迎交流。