这里每天分享一个 iOS 的新知识,快来关注我吧
前言
iPhone 越狱已经不是什么新鲜事,但是越狱之后意味着已经拿到了系统的所有权限,继续在越狱的设备上运行你的程序也就意味着不再安全,因此目前很多主流的 App 都是禁止运行在此类设备上的。
但是怎么判断一个设备是否为越狱的机器呢?今天就来讲讲我所知道的一些方法。
方法一
检查手机上是否安装了 Cydia ,玩越狱的同学肯定都清楚,这个 app
堪称是越狱系统的 App Store,上边可以安装各种正规 App Store 安装不到的软件。Cydia
上除了独立的应用程序之外,更多的包是 iOS 本身和应用程序的扩展、修改和主题。
因此可以说只要是越狱的设备,都会安装这个应用,那我们只需要检测这个应用存不存在就行了。
这里主要用到的方法是用 canOpenURL
是否能打开 cydia://
这个 URL Scheme。
csharp
func isJailBreak() -> Bool {
return UIApplication.shared.canOpenURL(URL(string: "cydia://")!)
}
这里记得把 cydia 加入到 info.plist 中的 LSApplicationQueriesSchemes 字段里才能正常检测应用是否安装
这种方式简单粗暴,不过不建议用,因为准确度可能不高,一方面 cydia
可能把这个 URL Scheme 改掉防止你检测。另一方面正常手机也可能会有一个 app 的 URL Scheme 叫这个名字,造成误判。
方法二
检测是否存在 MobileSubstrate
动态库,这个库是 cydia 的基石,越狱环境下安装绝大部分插件,必须要有 MobileSubstrate
,因此我们只需要判断是否存在这个动态库即可。
我在网上找了一个 c 语言的实现:
arduino
bool
isJailBreak(void)
{
const char *const imageName = "MobileSubstrate";
if (imageName != NULL) {
const uint32_t imageCount = _dyld_image_count();
for (uint32_t iImg = 0; iImg < imageCount; iImg++) {
const char *name = _dyld_get_image_name(iImg);
if (strstr(name, imageName) != NULL) {
return true;
}
}
}
return false;
}
方法三
还是检测文件,如果越狱的话,设备会创建许多文件,可以使用 FileManager
来检测这些文件是否存在:
csharp
func isJailBreak() -> Bool {
#if targetEnvironment(simulator)
return false
#else
let files = [
"/private/var/lib/apt",
"/Applications/Cydia.app",
"/Applications/RockApp.app",
"/Applications/Icy.app",
"/Applications/WinterBoard.app",
"/Applications/SBSetttings.app",
"/Applications/blackra1n.app",
"/Applications/IntelliScreen.app",
"/Applications/Snoop-itConfig.app",
"/bin/sh",
"/usr/libexec/sftp-server",
"/usr/libexec/ssh-keysign /Library/MobileSubstrate/MobileSubstrate.dylib",
"/bin/bash",
"/usr/sbin/sshd",
"/etc/apt /System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
"/System/Library/LaunchDaemons/com.ikey.bbot.plist",
"/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist",
"/Library/MobileSubstrate/DynamicLibraries/Veency.plist"
]
return files.contains(where: {
return FileManager.default.fileExists(atPath: $0)
})
#endif
}
这里有个条件编译,在模拟器下是不需要检查的。
方法四
越狱之后所有 App 都被授予 root 权限,并且可以修改沙箱之外的文件。利用这个特点,如果我们的 App 可以写入其沙箱之外的文件,则证明该设备已越狱:
php
func isJailBreak() -> Bool {
let string = "iOS 新知"
do {
try string.write(to: URL(filePath: "/private/myfile.txt"), atomically: true, encoding: .utf8)
return true
} catch {
return false
}
}
方法五
越狱之后也就意味着 App 可以随意调用系统 API 了,因此我们可以尝试调用系统 API,来查看是否能得到正确结果,以此来判断是否越狱:
swift
func isJailBreak() -> Bool {
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
let forkPtr = dlsym(RTLD_DEFAULT, "fork")
typealias ForkType = @convention(c) () -> Int32
let fork = unsafeBitCast(forkPtr, to: ForkType.self)
return fork() != -1
}
建议以上五种方法结合使用,提高检测的准确率。
检测到越狱设备,禁止使用
如果检测到当前运行环境为越狱设备,可以强制退出 App,以确保安全。强制退出 app 的方法就很多了,可以使用 exit(-1)
,也可以人为做个数组越界之类的:
scss
// 检测到越狱设备
if isJailBreak() {
// 退出 app
exit(-1)
// 或者数组越界 crash
// [0][1]
}
这里每天分享一个 iOS 的新知识,快来关注我吧
本文同步自微信公众号 "iOS新知",每天准时分享一个新知识,这里只是同步,想要及时学到就来关注我吧!