注册
iOS

如何判断设备是否越狱?

前言


iPhone 越狱已经不是什么新鲜事,但是越狱之后意味着已经拿到了系统的所有权限,继续在越狱的设备上运行你的程序也就意味着不再安全,因此目前很多主流的 App 都是禁止运行在此类设备上的。


但是怎么判断一个设备是否为越狱的机器呢?今天就来讲讲我所知道的一些方法。


方法一


检查手机上是否安装了 Cydia,玩越狱的同学肯定都清楚,这个 app 堪称是越狱系统的 App Store,上边可以安装各种正规 App Store 安装不到的软件。Cydia 上除了独立的应用程序之外,更多的包是 iOS 本身和应用程序的扩展、修改和主题。


因此可以说只要是越狱的设备,都会安装这个应用,那我们只需要检测这个应用存不存在就行了。


这里主要用到的方法是用 canOpenURL 是否能打开 cydia:// 这个 URL Scheme。

func isJailBreak() -> Bool {
    return UIApplication.shared.canOpenURL(URL(string: "cydia://")!)
}



这里记得把 cydia 加入到 info.plist 中的 LSApplicationQueriesSchemes 字段里才能正常检测应用是否安装



这种方式简单粗暴,不过不建议用,因为准确度可能不高,一方面 cydia 可能把这个 URL Scheme 改掉防止你检测。另一方面正常手机也可能会有一个 app 的 URL Scheme 叫这个名字,造成误判。


方法二


检测是否存在 MobileSubstrate 动态库,这个库是 cydia 的基石,越狱环境下安装绝大部分插件,必须要有 MobileSubstrate,因此我们只需要判断是否存在这个动态库即可。


我在网上找了一个 c 语言的实现:

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 来检测这些文件是否存在:

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 可以写入其沙箱之外的文件,则证明该设备已越狱:

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,来查看是否能得到正确结果,以此来判断是否越狱:

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),也可以人为做个数组越界之类的:

// 检测到越狱设备
if isJailBreak() {
    // 退出 app
    exit(-1)
    // 或者数组越界 crash
    // [0][1]
}

作者:iOS新知
链接:https://juejin.cn/post/7273435543676813375
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册