はじめに
こんにちはsuzukiです。本日はiOSの脱獄について、まとめて行きたいと思います。普段のアプリ開発ではあまり意識をせずに開発を行っていましたが、クライアントの要望で、脱獄を行なっているユーザーにはアプリが使用できなくしてほしいとのことです。脱獄を実際に行なったことはないため調査しながらまとめております。
脱獄とは
脱獄とは大まかに説明するとAppleがiPhoneにかけている様々な制限を解除し、端末のカスタマイズを行うことができるらしいです。デメリットとしては正規の状態とは判断されなくなるためAppleのサポートを受られなくなります。
開発者からするとiOSというOSの中で動くアプリを提供しているのであり、脱獄している端末に対して、動作保証外で起動できない状態にしたいです。
個人的な見解ですが、脱獄はしない方が無難かなと思っております。
脱獄のチェックについて
本題の脱獄のチェックについて説明して行きます。
Cydiaのチェック
脱獄後Cydiaというアプリケーションでアプリの配布が行われる為、Cydiaを使用できる状態であれば脱獄されている状態という判断を行なっても良さそうです。
Cydiaが端末上に存在するかURLSchemeを使ってチェックしましょう。
URLSchemeの設定方法なのですが、こちらのサイトがわかりやすいです。
まずはInfo.plistを編集してLSApplicationQueriesSchemesの項目を追加してcydiaをアプリから呼べるようにします。
こちらの設定でアプリからCydiaアプリのスキームを呼び出す準備ができました。それでは実際に呼び出せるかを確認するコードを記述します。
Cydiaのファイルパスが存在するかとCydiaを呼び出せるかを確認しています。
1 2 3 4 5 6 7 8 9 | //Cydiaのチェック var checkCydia: Bool{ //Cydiaのチェックを行う if FileManager.default.fileExists(atPath: "/Applications/Cydia.app")||UIApplication.shared.canOpenURL(URL(string: "cydia://")!){ //Cydiaのパスが存在するため脱獄と判断 return true } return false } |
上記のコードでtrueが返却されればCydiaが存在するということを検知できます。
しかしながら脱獄をしているユーザーが全てCydiaを利用しているとは限りません。そのためCydiaのチェックだけでは十分と言えません(ウィルスと一緒で十分と言える状態はないのかもしれませんが、、、)
他の方法でのチェックもしてみましょう。
パスのチェック
iOSを普通に使っている範囲では本来作成されない箇所にファイル/フォルダが作成されている場合は脱獄されていると判断できます。
しかしながら脱獄する方法で作成されるパスが異なるため何をチェックすればいいとは明言できません。
今回はこちらの記事を参考にパスのチェックをしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //Passのチェック var checkPass: Bool{ // ファイルが存在するか確認を行うiOS端末では存在しない if 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/"){ //パスが存在したため脱獄と判断 return true } return false } |
こちらでパスのチェックをいたしました。
後ほど触れますが、こちらのチェックの一部がiOSシミュレーターで起動すると引っかかります。
書き込み権限のチェック
アプリから本来アクセス権限がないファイルをアクセス、編集できる場合は脱獄されていると判断できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //ファイルの書き込み権限のテスト var checkWritable: Bool{ // 本来であれば書き込みの権限がない箇所に書き込みができるかチェック let stringToWrite = "Jailbreak" do{ try stringToWrite.write(toFile:"/private/JailbreakTest.txt", atomically:true, encoding:String.Encoding.utf8) //書き込めたため脱獄と判断 return true }catch{ return false } } |
iOSシミュレーターのチェックを行わない。
Passのチェックを行うとiOSシミュレーターはチェックに引っかかり脱獄されていると判断されてしまいます。
そのためiOSシミュレーターでは脱獄のチェックを行わないように設定を行います。
1 2 3 4 5 6 7 8 9 | //脱獄のチェック var isJailBroken :Bool{ if TARGET_OS_SIMULATOR != 1{ if checkCydia||checkPass||checkWritable{ return true } } return false } |
- Cydiaのチェック
- パスのチェック
- 書き込み権限のチェック
iOSシミュレーター以外で上記のチェックが行われます。
Appleの審査もあるためiOSシミュレーターは動く状態にした方が良さそうです。
コードまとめ
念のため今回のコードをこちらに記述いたします。
isJailBrokenを呼び出して脱獄の判断を行えます。
念のため関数名は変更した方がいいかもしれません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //脱獄のチェック var isJailBroken :Bool{ if TARGET_OS_SIMULATOR != 1{ if checkCydia||checkPass||checkWritable{ return true } } return false } //Cydiaのチェック var checkCydia: Bool{ //Cydiaのチェックを行う if FileManager.default.fileExists(atPath: "/Applications/Cydia.app")||UIApplication.shared.canOpenURL(URL(string: "cydia://")!){ //Cydiaのパスが存在するため脱獄と判断 return true } return false } //Passのチェック var checkPass: Bool{ // ファイルが存在するか確認を行うほiOS端末では存在しないディレクトリのチェック if 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/"){ //パスが存在したため脱獄と判断 return true } return false } //ファイルの書き込み権限のテスト var checkWritable: Bool{ // 本来であれば書き込みの権限がない箇所に書き込みができるかチェック let stringToWrite = "Jailbreak" do{ try stringToWrite.write(toFile:"/private/JailbreakTest.txt", atomically:true, encoding:String.Encoding.utf8) //書き込めたため脱獄と判断 return true }catch{ return false } } |
さいごに
最後までお付き合いありがとうございます。
途中でも記述しましたがチェックすべき内容は日々変わっていくかと思います。あまり自分も知見がないため、フレームワークなどあればそちらに任せたい内容ですね。