我如何检测一个 iOS 应用程序运行在越狱的手机上?

如果我希望我的应用程序在越狱的 iPhone 上有不同的表现,我该如何确定这一点呢?

90283 次浏览

我建议寻找不存在于“普通”iPhone 上的文件。我见过的所有越狱工具包都安装了 ssh。这可能是越狱电话的好迹象。

那要看你说的越狱是什么意思了。在这个简单的例子中,您应该能够看到是否安装了 Cydia,然后根据这一点进行操作——类似于

NSString *filePath = @"/Applications/Cydia.app";
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
// do something useful
}

对于被破解的内核,它涉及的内容更多一些。

检查内核是否被破坏并没有那么复杂。

破解使得内核对签名代码的签名检查总是报告代码签名正确,未破解的手机无法运行带有错误签名的代码。

因此,在应用程序中包含一个带有错误签名的单独可执行文件。它可以只是一个包含 main ()和返回值的3行程序。编译不需要代码签名的可执行文件(在 Project Settings-> Build 中关闭它) ,并使用“ codesign”命令行实用工具使用不同的键签名。

让你的应用程序执行独立的可执行文件。如果您的程序在运行带有错误信号的单独可执行文件时无法获得返回值,那么它肯定会被监禁。如果单独的可执行文件返回 A-OK,那么电话肯定是越狱了。

BOOL isJailbroken()
{
#if TARGET_IPHONE_SIMULATOR
return NO;
#else
FILE *f = fopen("/bin/bash", "r");


if (errno == ENOENT)
{
// device is NOT jailbroken
fclose(f);
return NO;
}
else {
// device IS jailbroken
fclose(f);
return YES;
}
#endif
}

我不知道任何“ API”存在这一点。如果有,那么一个越狱掩蔽产品将很快掩盖他们。

正如许多人指出的那样,这是一场猫捉老鼠的游戏。当两个玩家都成为专家之后,一切就取决于谁先出手了。(持有该设备的人)

我在 Zdziarski 的新书《黑客入侵和 iOS 应用程序安全》中发现了许多有关越狱的好建议。(就我个人而言,我为 O’Reilly 电子书支付了更多费用,因为他们允许复制和粘贴。)

不,我和出版商没有关系。但我觉得这是本好书。我不喜欢只是公布黑客的错误,这样他们就可以修复它们,所以我想我应该指向这本书。

尝试访问/应用程序/Preferences.app/General.plist 你应该可以在越狱的 iPhone 上这么做 在非工作电话上你将无法访问它

+(BOOL)isJailbroken {
NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"];
return [[UIApplication sharedApplication] canOpenURL:url];
}

检查文件路径 /Applications/Cydia.app是不允许在一个正常的电话?我从来没有听说过苹果发现这个问题并拒绝一个应用程序,但是苹果是不可预测的。Cydia 有 网址资料库://,可以用 UIApplicationcanOpenURL:合法地检查它

我们所做的是,我们已经有了一个 RSS 提要与我们的用户交流(股市直播) ,我们把一个新闻项目,这样说:

一些破解设备有问题等等等等,我们做了一个黑客来解决这些问题,但我们需要知道这是否是一个破解设备,按这里,以便应用程序修复这个问题。如果你恢复正常了。

然后你处理用户交互,做适当的事情,比如行为不同等等。

尝试找到一个文件,Cydia 或越狱设备创建。或者尝试写入应用程序黑盒外的文件。如果您成功地做到了这一点,该设备就会受到威胁/越狱:)

- (BOOL)jailbroken
{
NSFileManager * fileManager = [NSFileManager defaultManager];
return [fileManager fileExistsAtPath:@"/private/var/lib/apt/"];
}

尝试通过应用程序执行无符号代码。

越狱装置通常具有以下特点:

  • 运行无符号代码
  • Cydia 安装了
  • 有越狱文件
  • 对整个文件系统的完全 r/w 访问
  • 一些系统文件将被修改(内容和 sha1与原始文件不匹配)
  • 坚持特定版本(越狱版本)

仅仅检查文件是否存在以进行越狱检测是注定要失败的。 这些检查很容易绕过。

我所知道的最复杂的方法是使用 objc_copyImageNames()函数。它返回一个当前加载的库列表,因为大多数人在越狱设备上使用 MobileSublate,而且大多数 iAP 破解工具都依赖于它,所以至少会出现一些 MobileSublate 库。

您可以通过检查以下内容来检测设备是否破解:

  • Cydia 安装好了
  • 验证一些系统路径
  • 执行沙箱完整性检查
  • 执行符号链接验证
  • 验证是否在沙箱外创建和写入文件

有一个我从各种文章和书籍中创建的开源库!

这是一个代码,它结合了我找到的一些答案来满足这个需求,并且会给你更高的成功率:

BOOL isJailbroken()
{
#if !(TARGET_IPHONE_SIMULATOR)


if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/Library/MobileSubstrate/MobileSubstrate.dylib"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/bin/bash"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/usr/sbin/sshd"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt"] ||
[[NSFileManager defaultManager] fileExistsAtPath:@"/private/var/lib/apt/"] ||
[[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]])  {
return YES;
}


FILE *f = NULL ;
if ((f = fopen("/bin/bash", "r")) ||
(f = fopen("/Applications/Cydia.app", "r")) ||
(f = fopen("/Library/MobileSubstrate/MobileSubstrate.dylib", "r")) ||
(f = fopen("/usr/sbin/sshd", "r")) ||
(f = fopen("/etc/apt", "r")))  {
fclose(f);
return YES;
}
fclose(f);


NSError *error;
NSString *stringToBeWritten = @"This is a test.";
[stringToBeWritten writeToFile:@"/private/jailbreak.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];
[[NSFileManager defaultManager] removeItemAtPath:@"/private/jailbreak.txt" error:nil];
if(error == nil)
{
return YES;
}


#endif


return NO;
}

要检查的一些常见文件: /Library/MobileSubstrate/MobileSubstrate.dylib

/Applications/Cydia.app

/var/cache/apt

/var/lib/apt

/var/lib/cydia

/var/log/syslog

/var/tmp/cydia.log

/bin/bash

/bin/sh

/usr/sbin/sshd

/usr/libexec/ssh-keysign

/etc/ssh/sshd_config

/etc/apt

大多数人检查与 Cydia 相关的文件。

我在 Swift 2.3中重新编写了@Yossi 提供的解决方案

public static func jailbroken(application: UIApplication) -> Bool {
guard let cydiaUrlScheme = NSURL(string: "cydia://package/com.example.package") else { return isJailbroken() }
return application.canOpenURL(cydiaUrlScheme) || isJailbroken()
}




static func isJailbroken() -> Bool {


if isSimulator {
return false
}


let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath("/Applications/Cydia.app") ||
fileManager.fileExistsAtPath("/Library/MobileSubstrate/MobileSubstrate.dylib") ||
fileManager.fileExistsAtPath("/bin/bash") ||
fileManager.fileExistsAtPath("/usr/sbin/sshd") ||
fileManager.fileExistsAtPath("/etc/apt") ||
fileManager.fileExistsAtPath("/usr/bin/ssh") {
return true
}


if canOpen("/Applications/Cydia.app") ||
canOpen("/Library/MobileSubstrate/MobileSubstrate.dylib") ||
canOpen("/bin/bash") ||
canOpen("/usr/sbin/sshd") ||
canOpen("/etc/apt") ||
canOpen("/usr/bin/ssh") {
return true
}


let path = "/private/" + NSUUID().UUIDString
do {
try "anyString".writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding)
try fileManager.removeItemAtPath(path)
return true
} catch {
return false
}
}


static func canOpen(path: String) -> Bool {
let file = fopen(path, "r")
guard file != nil else { return false }
fclose(file)
return true
}

以下是我的解决方案: 第一步

extension UIDevice {
func isJailBroken() -> Bool {
let cydiaPath = "/Applications/Cydia.app"
let aptPath = "/private/var/lib/apt/"
if FileManager.default.fileExists(atPath: cydiaPath) || FileManager.default.fileExists(atPath: aptPath) {
return true
}
return false
}
}

步骤2: 在启动屏幕视图控制器(或者你第一次调用的 VC)中的 viewDidLoad()中调用它:

       // show a blank screen or some other view controller
let viewController = UIDevice.current.isJailBroken() ? JailBrokenViewController() : NextViewController()
self.navigationController?.present(viewController, animated: true, completion:nil)

Swift 4及以上版本请使用以下代码: 在 appcommittee 中添加以下代码:

private func getJailbrokenStatus() -> Bool {
if TARGET_IPHONE_SIMULATOR != 1 {
// Check 1 : existence of files that are common for jailbroken devices
if FileManager.default.fileExists(atPath: "/Applications/Cydia.app")
|| FileManager.default.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib")
|| FileManager.default.fileExists(atPath: "/bin/bash")
|| FileManager.default.fileExists(atPath: "/usr/sbin/sshd")
|| FileManager.default.fileExists(atPath: "/etc/apt")
|| FileManager.default.fileExists(atPath: "/private/var/lib/apt/")
|| UIApplication.shared.canOpenURL(URL(string:"cydia://package/com.example.package")!) {
return true
}
// Check 2 : Reading and writing in system directories (sandbox violation)
let stringToWrite = "Jailbreak Test"
do {
try stringToWrite.write(toFile:"/private/JailbreakTest.txt", atomically:true, encoding:String.Encoding.utf8)
//Device is jailbroken
return true
} catch {
return false
}
}
else {
return false
}
}

在 Appcommittee 方法内部,编写如下代码

func applicationDidBecomeActive (_ application: UIApplication) {
    

if getJailbrokenStatus() {
let alert = UIAlertController(title: LocalizedKeys.Errors.jailbreakError, message: LocalizedKeys.Errors.jailbreakErrorMessage, preferredStyle: UIAlertController.Style.alert)
let jailBrokenView = UIViewController()
        

jailBrokenView.view.frame = UIScreen.main.bounds
jailBrokenView.view.backgroundColor = .white
self.window?.rootViewController = jailBrokenView
jailBrokenView.present(alert, animated: true, completion: nil)
}
    

if #available(iOS 11.0, *) {
if !UIScreen.main.isCaptured {
DispatchQueue.main.async {
self.blockImageView.removeFromSuperview()
}
}
}
}

在 iOS14中有一个服务 应用程序证明。检查这个 文章

此外,我使用这个回购 https://github.com/fiber-inc/SecurityDetector,但一些用户告诉,他们没有越狱,当检测器触发。

所以我决定测试这个回购 https://github.com/wearebeatcode/SwiftJailbreakDetection/blob/master/Sources/SwiftJailbreakDetection/JailbreakDetection.swift。不过算法还是不太好,给出的结果是,越狱活动在非越狱手机。继续搜索。.

现在我试试这个: https://github.com/securing/IOSSecuritySuite