【问题标题】:How do I detect that an iOS app is running on a jailbroken phone?如何检测 iOS 应用程序正在越狱手机上运行?
【发布时间】:2012-03-22 20:43:34
【问题描述】:

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

【问题讨论】:

标签: ios iphone jailbreak


【解决方案1】:

我建议寻找“香草”iPhone 上不存在的文件。我见过的所有越狱工具包都安装了 ssh。这可能是越狱手机的一个很好的指标。

【讨论】:

  • ssh 不会自动安装,用户必须自己安装。
  • 我还没有真正跟上越狱的场景。但我记得,当我写这篇文章时(2009 年 1 月),Ziphone 和其他人默认安装了 ssh 和 bsd 子系统。也许这不再是真的了。
  • 相信我,chpwn 已经跟上越狱场景了。
【解决方案2】:

这取决于您所说的越狱是什么意思。在简单的情况下,您应该能够查看是否安装了 Cydia 并通过它 - 类似于

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

对于被黑的内核,它涉及更多一点(很多)。

【讨论】:

  • 在您的沙箱之外寻找 any 文件/目录还不够吗?喜欢 /etc?
  • 请注意,并非所有用户都安装了 Cydia -- 这不是一个好的检查,您应该检查 /all/ users /will/ 拥有的 /bin/bash 之类的东西。
  • apt 在哪里存储它的信息?或者我可以调用一个 system() 命令并找出答案。我想知道他们是否有某些应用,如果有,则限制应用
  • @RazorSharp 在这一点上,几乎所有用户都拥有 Cydia。现在检查一下可能就足够了。但是,如果您想要 100% 可靠的检查,则需要使用基于内核的检查,如下所示。
  • FWIW 文件检查很容易绕过。可以使用 mobilesubstrate 挂钩 fileExistsAtPath: 并使其返回 NO 以获取您检查的特定路径。
【解决方案3】:

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

越狱使内核对签名代码的签名检查始终报告代码签名正确,未破解的手机无法运行签名错误的代码。

因此,请在应用程序中包含一个签名错误的单独可执行文件。它可能只是一个具有 main() 和返回值的 3 行程序。在没有代码签名的情况下编译可执行文件(在项目设置->构建中将其关闭)并使用“codedesign”命令行实用程序使用不同的密钥对其进行签名。

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

【讨论】:

  • 你能通过App Store获得一个签名无效的(子)可执行文件吗?
  • 也许事情已经发生了变化,但执行单独的可执行文件不会阻止您被批准进入应用商店吗?
  • 有人可以回答以前的 cmets 吗?这是很重要的问题。
  • 没有人会真正阻止您将带有无效签名的 Mach-O 写入磁盘。但是,我不同意不涉及检查内核是否损坏的答案,或者这是任何方式的确定性检查。
【解决方案4】:
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
}

【讨论】:

  • 这是一个很好的解决方案,但是 xCon 和其他类似的工具可以轻松绕过此检查。所以,我正在寻找更好的解决方案。
  • @AlexeiRobsky 没有完美的解决方案。总会有人想办法绕过你的保护,这只是事实。
【解决方案5】:

我不知道为此存在任何“API”。如果有,那么越狱屏蔽产品会很快掩盖它们。

正如很多人指出的那样,这是一场猫捉老鼠的游戏。在两位玩家都成为专家之后,这一切都归结为谁先出手。 (手持设备的人。)

我在 Zdziarski 的新书《Hacking and Securing iOS Apps》中找到了很多检测越狱的好建议。 (就我个人而言,我为 O'Reilly 电子书支付了更多费用,因为它们允许复制和粘贴。)

不,我不隶属于出版商。但我确实发现这是一本好书。我不喜欢仅仅发布黑客的错误以便他们修复它们,所以我想我会指向这本书。

【讨论】:

    【解决方案6】:

    尝试访问 /Application/Preferences.app/General.plist 您应该可以在越狱的 iPhone 上执行此操作 在非 Jb 手机上,您将无法访问它

    【讨论】:

    • 这个答案在源代码中会更有趣。恕我直言:这将为您赢得一票。
    • -1 = 未越狱设备也可以打开和读取此文件。 (已测试)
    • @JohanKarlsson 我假设这里的读者可以编写自己的源代码。如果他们不能 - 他们在这里做什么?
    【解决方案7】:
    +(BOOL)isJailbroken {
        NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"];
        return [[UIApplication sharedApplication] canOpenURL:url];
    }
    

    普通手机不允许查看文件路径/Applications/Cydia.app?我从未听说过 Apple 检测到这一点并拒绝为此应用程序,但 Apple 是不可预测的。 Cydia 有a URL scheme cydia:// 可以通过 UIApplication canOpenURL: 合法检查

    【讨论】:

    • 这是一个很好的检查方法,它不会超出您的沙箱。当然,如果越狱者没有安装 Cydia,它会返回 NO,但我认为大多数越狱者都安装了 Cydia。
    • 应用被破解时这个字符串不能改吗?
    • 对于iOS9.0+你还需要在app plist中添加LSApplicationQueriesSchemes key。否则 canOpenURL 将始终返回 false。
    • 如果用户安装了符合 cydia:// 方案(如 InstantTV)的应用程序,这将提供误报。
    • @thattyson 谢谢!我正在寻找检查为什么我得到误报
    【解决方案8】:

    我们所做的是,我们已经有一个 RSS 提要与我们的用户交流 (Stocks Live),我们放置了一个新闻项目,内容如下:

    一些越狱设备有问题 bla bla bla,我们进行了破解来解决这些问题,但我们需要知道这是否是越狱设备,请按此处以便应用程序解决问题。如果您恢复正常,即解除越狱,请按此处。

    然后你处理用户交互并做适当的事情,比如表现不同等......

    【讨论】:

      【解决方案9】:

      尝试查找 cydia 或越狱设备创建的文件。或者尝试在应用程序黑盒之外的文件中写入。如果您成功执行此操作,则设备已被盗用/越狱:)

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

      【讨论】:

      • Apple 批准了包含上述代码的应用程序?
      【解决方案10】:

      尝试通过您的应用程序执行未签名的代码。

      越狱设备通常具有以下特点:

      • 运行未签名的代码
      • 已安装 Cydia
      • 有越狱文件
      • 对整个文件系统的完全读写访问权限
      • 部分系统文件将被修改(内容等 sha1 与原始文件不匹配)
      • 卡在特定版本(越狱版)

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

      【讨论】:

      • 尝试执行未签名的代码会使您的应用被应用商店拒绝
      【解决方案11】:

      我知道的最复杂的方法是使用objc_copyImageNames() 函数。它返回当前加载的库列表,由于大多数人在越狱设备上都有 MobileSubstrate 并且大多数 iAP 破解工具都依赖它,因此至少会显示一些 MobileSubstrate 库。

      【讨论】:

      • 您有关于 MobileSubstrate/CydiaSubstrate 库的链接吗?我没有越狱的手机可以玩,所以我开车“盲目”,谷歌搜索基本上会出现你上面的评论。
      • @chadbag 我也没有,但你可以查找 MobileSubstrate 的 deb 文件,解压它并将(几乎)所有的 .dylib 列入黑名单。
      • 谢谢,我找到了一些代码,我可能会根据您的评论添加更多内容。非常感谢!
      【解决方案12】:

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

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

      我根据各种文章和书籍创建了一个开源库。 Try it out on GitHub!

      【讨论】:

        【解决方案13】:

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

        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;
        }
        

        【讨论】:

        • @Porizm,这只是我找到的一些答案的组合。其中一些对我不起作用,但对其他人起作用..所以使用此代码您不会冒险..如果您使用它,您可以 99% 确定。关于性能,您每次运行只能运行一次并将答案保存在某处,您不必每次都运行它..
        • @yossi 和 porizm apple 批准了您包含上述代码的应用程序?请回复
        • 这个方法应该是一个内联的 C 函数,不是 Objective-C。发现和绕过 Objective-C 方法太容易了,特别是如果你称之为isJailbroken
        • @Yossi 这是否涵盖使用 Taig 越狱的设备?
        • @Lakshay 我不知道.. 不仅邀请您检查并在此处添加答案 :)
        【解决方案14】:

        需要检查的一些常见文件: /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 相关文件。

        【讨论】:

          【解决方案15】:

          我在 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
          }
          

          【讨论】:

            【解决方案16】:

            这是我的解决方案: 第 1 步

            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)
            

            【讨论】:

              【解决方案17】:

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

              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
                  }
              }
              

              在 Appdelegate 方法中,编写如下代码

              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()
                          }
                      }
                  }
              }
              

              【讨论】:

              • self.blockImageView.removeFromSuperview() 出现错误,请建议如何处理
              【解决方案18】:

              在 iOS 14 中有一项服务 App Attest。检查这个article

              我也使用了这个 repo https://github.com/fiber-inc/SecurityDetector,但有些用户告诉他们,当检测器触发时,他们没有越狱。

              所以我决定测试这个 repo https://github.com/wearebeatcode/SwiftJailbreakDetection/blob/master/Sources/SwiftJailbreakDetection/JailbreakDetection.swift。算法仍然不好,并给出越狱活动在未越狱手机中的结果。进一步搜索..

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

              【讨论】:

                猜你喜欢
                • 2011-09-25
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-10-23
                • 2012-06-24
                相关资源
                最近更新 更多