Jailbreak Detectionは、iOSデバイス上のジェイルブレイクの有無を検出し、制限が解除された環境でのアプリケーションの実行を防ぐメカニズムのセットです。ジェイルブレイクはサンドボックスの外側のファイルシステムへのアクセスを提供し、変更されたライブラリのインストールやシステムコールのインターセプトを可能にします。Apple Security Documentation (2024)によると、ジェイルブレイクされたデバイスはSecure Bootセキュリティモデルに準拠していません。Jailbreak Detectionは、ファイルインジケータのチェック、ランタイムコール分析、およびサンドボックス署名の整合性検証を組み合わせます。
重要なポイント
Jailbreak Detectionは、オペレーティングシステムの制限が解除されたiOSデバイスを識別するプロセスです。ジェイルブレイクはiOSカーネルを変更し、コード署名を無効にし、完全なファイルシステムへのアクセスを提供し、許可されていないライブラリのロードを可能にします。そのようなデバイスで実行されるアプリケーションには、ランタイム環境の整合性の保証がありません。どのプロセスでもアプリケーションのメモリを読み取り、独自の証明書をシステムトラストストアにインストールしてSSL/TLSトラフィックをインターセプトし、Cydia SubstrateやSubstituteを介してコードを注入できます。
iOS上の金融アプリケーションは、PCI DSS標準の要件に従ってJailbreak Detectionを実装する必要があります — 認定を受けるには、アプリケーションが侵害されたデバイスで実行されていないことを証明する必要があります。OWASP Mobile Security (2024)は、Jailbreak Detectionの欠如を脆弱性M8として分類しています。App Storeアプリケーションの場合、Appleはジェイルブレイクされたデバイスでの機能ブロックを禁止していませんが、変更される可能性があるクライアントコードのみに依存しないよう、クライアント側とサーバー側のチェックを組み合わせることを推奨しています。
サンドボックスモデルのため、iOSでのJailbreak DetectionのアーキテクチャはAndroidでのRoot Detectionよりも複雑です。Androidでは、アプリケーションは/procを読み取ってシステムを分析できます。iOSサンドボックスは、ほとんどのシステムインジケータへの直接アクセスをブロックします。開発者は、canAccessFile APIを介した制限ゾーンでのファイル可用性のチェックや、exitコード検証付きのfork()を介した子プロセスの起動などの代替手法を使用せざるを得ません。現代のチェックは、ジェイルブレイク下でのみ可能なアクションを試行し、結果を分析することに基づいています。
最もシンプルで歴史的に最初のアプローチは、ジェイルブレイクされたデバイスにのみインストールされるファイルやアプリケーションの存在をチェックすることです。シンプルさにもかかわらず、ファイルチェックは防御の基本層として残っています。なぜなら、それらをバイパスするにはユーザーの能動的なアクションが必要だからです。
ジェイルブレイクされたデバイスには、Cydia、Sileo、Zebra、またはInstallerなどのアプリケーションが存在します。それらの存在はNSFileManagerを介してチェックされます:[[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"]。unc0ver、checkra1n、Taurine、Chimeraのパッケージも同様にチェックされます。これらのチェックは、NSFileManager呼び出しをインターセプトするHideJBツイークを介してバイパスできます。
ジェイルブレイクは、標準のiOSでは利用できないUNIXユーティリティをインストールします:apt、dpkg、ssh、rsync、sftp、dd、readlinkなど。/usr/bin/ssh、/bin/bash、/bin/sh、/usr/libexec/sftp-serverの存在がチェックされます。これらのファイルのいずれかが正常に検出された場合、ジェイルブレイクの可能性が高くなります。iOS 13–17では、/var/jbの存在をチェックすることも重要です — unc0verとTaurineのブートストラップルートディレクトリです。
MobileSubstrate (CydiaSubstrate.dylib)とSubstituteは、プロセスにコードを注入するためのライブラリです。それらの存在は、RTLD_NOLOADフラグを指定したdlopen()を介してチェックされます。ライブラリがアドレス空間にロードされている場合 — プロセスはジェイルブレイク環境で実行されています。これはより信頼性の高いチェックです。HideJBはプロセスに既にロードされているライブラリをアンロードできないためです。
- (BOOL)isJailbrokenByFiles {
NSArray *paths = @[
@"/Applications/Cydia.app",
@"/Applications/Sileo.app",
@"/Applications/Zebra.app",
@"/usr/bin/ssh",
@"/bin/bash",
@"/var/jb",
@"/etc/apt"
];
for (NSString *path in paths) {
if ([[NSFileManager defaultManager]
fileExistsAtPath:path]) {
return YES;
}
}
return NO;
}
- (BOOL)isSubstrateLoaded {
void *handle = dlopen(
"/Library/MobileSubstrate/MobileSubstrate.dylib",
RTLD_NOLOAD | RTLD_LAZY
);
if (handle) {
dlclose(handle);
return YES;
}
return NO;
}
動的チェックは、iOSサンドボックスで禁止されているアクションを実行し、結果を分析します。アクションがブロックされなかった場合 — デバイスはおそらくジェイルブレイクされています。
標準のiOSでは、fork()呼び出しはerrno = EPERMで-1を返します。ジェイルブレイクされたデバイスでは、サンドボックスの制限が解除されているため、fork()が成功する可能性があります。このチェックは信頼性がありますが、一部のiOSバージョンで誤検出を引き起こす可能性があります。fork()は、子プロセスを起動する能力をチェックするためにposix_spawn()に置き換えることもできます。
制限ゾーンでのファイル読み取りの試行:/etc/master.passwd、/var/log/system.log、/private/var/cache。標準のiOSでは、これらの読み取りはエラーを返します。アプリケーションがこれらのファイルを正常に読み取った場合 — サンドボックスは無効になっています。さらに、/private/への書き込み能力がチェックされます — サンドボックスでは、すべてのシステムパーティションが通常のアプリケーションに対して読み取り専用でマウントされています。
ジェイルブレイクは、dyld共有キャッシュを含むシステムライブラリを変更します。システムフレームワークまたは個々のシンボルのハッシュをチェックすると、変更が明らかになる可能性があります。iOS 14+では、sysctl kern.versionを読み取ることで、カーネルアドレス空間内のjit_region_createシンボルやFugu14/checkra1n動作の他の兆候の存在がチェックされます。
- (BOOL)isJailbrokenByRuntime {
// fork()のチェック
int pid = fork();
if (pid == 0) {
exit(0);
}
if (pid > 0) {
waitpid(pid, NULL, 0);
return YES;
}
// システムファイルへのアクセスのチェック
FILE *f = fopen("/etc/master.passwd", "r");
if (f) {
fclose(f);
return YES;
}
// sysctl kern.versionのチェック
size_t size = 0;
sysctlbyname("kern.version", NULL, &size, NULL, 0);
if (size > 0) {
char *version = malloc(size);
sysctlbyname("kern.version", version, &size, NULL, 0);
NSString *str = [NSString stringWithUTF8String:version];
free(version);
if ([str containsString:"pwned"]) {
return YES;
}
}
return NO;
}
Swiftコードは簡単に逆アセンブルされ、Substrateを介してバイパスされます。libobjcとCシステム関数への直接呼び出しを使用したObjective-Cでのネイティブ実装は、チェックをバイパスに対して大幅に耐性のあるものにします。
libcのstat()呼び出しは、Objective-Cレベルでインターセプトできません。NSFileManagerメソッドをインターセプトするHideJBツイークはstat()に影響しません。stat()を使用したネイティブチェックは、HideJBモジュールがインストールされたデバイスでもファイルインジケータを検出します。ファイル用のstat()とライブラリ用のRTLD_NOLOAD付きdlopen()の組み合わせは、重複しない2つの検出チャネルを提供します。
ネイティブ関数SecStaticCodeCheckValidityは、Apple証明書に対するアプリケーションのコード署名を検証します。ジェイルブレイクされたデバイスでは、このチェックはカーネルパッチを介して偽装される可能性があります。偽装を回避するには、Swift Bridgeを介するのではなく、Security.frameworkからdlopen()を介した呼び出しを使用してネイティブコードからチェックを実行する必要があります。
#import <sys/stat.h>
#import <dlfcn.h>
- (BOOL)nativeCheckForJailbreak {
// stat()はNSFileManagerフックをバイパス
struct stat st;
if (stat("/Applications/Cydia.app", &st) == 0) {
return YES;
}
// ロードせずにSubstrateをチェックするためのdlopen
void *substrate = dlopen(
"/Library/MobileSubstrate/MobileSubstrate.dylib",
RTLD_NOLOAD
);
if (substrate) {
dlclose(substrate);
return YES;
}
return NO;
}
堅牢な保護を構築するには、バイパス技術を理解することが不可欠です。現代のバイパスツールは活発に進化しており、チェックの静的セットは数ヶ月で効果がなくなります。
HideJBは、NSFileManager、stat()、dlopen()、fork()への呼び出しをインターセプトし、戻り値を置き換えるツイークです。HideJBはCydia Substrateレベルで動作し、Objective-CとCの両方の関数をインターセプトします。iOS 15–16用のHideJB(Shadow)のバージョンは、カーネルレベルのフック手法を使用します。対策:フックチェーンを断ち切るために、IPCを介した結果配信を持つ別のプロセスでチェックを実行します。
Choicyは、特定のプロセスに対してSubstrateを無効にすることを可能にします。ユーザーは保護されたアプリケーションのインジェクションを無効にするだけで、すべてのライブラリチェックがfalseを返します。Liberty Liteは、人気のある保護ライブラリのほとんどのチェックをカバーする包括的なバイパスです。対策:DeviceCheckとApp Attestを介したサーバー側の検証 — サーバーは、ジェイルブレイクされたデバイスで偽造できない有効なApple証明書をデバイスが持っていることを検証します。
Fugu14やKFDなどのカーネルエクスプロイトは、カーネル空間でコードを実行し、アプリケーションが認識する前にシステムコールをインターセプトすることを可能にします。このレベルでは、stat()とfork()のチェックは効果がなくなります。唯一の信頼できる対策は、デバイスがApple Attestation手順を通過したことを検証するサーバー側のアテステーションです。このプロトコルはSecure Enclave内部の暗号鍵に基づいており、カーネルレベルのエクスプロイトでも読み取ることができません。
効果的なJailbreak Detectionを構築するには、ジェイルブレイク中にどのiOSセキュリティメカニズムが無効になるかを理解する必要があります。
iOSは署名チェックのシーケンスを介して起動します:Boot ROM → iBoot → iOS Kernel。ジェイルブレイクがbootromエクスプロイト(checkra1n)を使用する場合、セキュアブートチェーン全体が危険にさらされます — アプリケーションレベルのチェックは無意味です。ソフトウェアのみのエクスプロイト(unc0ver、Taurine、Fugu14)が使用される場合、ブートチェーンは破られておらず、App AttestなどのAppleサービスは信頼されたままです。
iOS 10以降、AppleはKPPを導入しました — 200ミリ秒ごとにカーネルの整合性を再検証するハードウェア保護です。すべての最新のジェイルブレイク(iOS 14–17)はPACまたはAPRRを介したKTRRバイパスを使用しますが、KPPは変更されたsysctlシステムテーブルの形で痕跡を残します。pwned、prod、または非標準バージョンのxnuなどの文字列の存在についてkern.versionをチェックすると、カーネルパッチが明らかになる可能性があります。
iOSサンドボックスは、entitlementsを使用してTrustedBSDレベルで動作します。ジェイルブレイクはサンドボックスプロファイルをallow-allに置き換えます。アプリケーションは、Documentsディレクトリの外側のファイルを読み取ろうとすることでサンドボックスを検証できます。成功した場合 — サンドボックスが変更されています。サンドボックスの整合性は、カーネルレベルのエクスプロイトなしでは偽造できない数少ないインジケータの1つです。許可チェックはインターセプトされる前にカーネルで実行されるためです。
よくある質問
AndroidのRoot DetectionはsuバイナリとMagiskの存在をチェックします。iOSのJailbreak DetectionはCydia、Sileo、MobileSubstrateを探し、fork()を実行する能力をチェックし、システムファイルを読み取ります。iOSサンドボックスのアーキテクチャはAndroidよりも厳格なため、iOSのチェックはシステムインジケータを読み取るよりも、禁止されているアクションの実行を試みることに依存しています。
はい、iOS 16–17ではDopamine、palera1n、checkra1nのジェイルブレイクが関連しています。Jailbreak Detectionは動作しますが、新しいツールに対応するためにチェックの更新が必要です。iOS 17ではAppleがサンドボックスを強化し、XNUの変更により多くの古いチェック(例えばfork())が信頼できなくなりました。
最も簡単な方法はHideJBまたはShadowで、ライブラリレベルでチェックをインターセプトします。より複雑な保護の場合は、特定のアプリケーションのインジェクションを無効にするためにFridaまたはChoicyが使用されます。サーバー側のアテステーション(App Attest)は、Secure Enclaveのハードウェアキーを置き換えるカーネルレベルのエクスプロイトを介してのみバイパスでき、現実的には不可能です。
ジェイルブレイクされたデバイス上のアプリケーションは以下にさらされる可能性があります:信頼できるストアの変更によるSSLトラフィックのインターセプト、ファイルシステムアクセスによるキーチェーンの読み取り、トークン処理メソッドのインターセプトを伴うSubstrateを介したコードインジェクション、および暗号化キーを取得するためのメモリダンプ。
App Attestは、アプリケーションとデバイスの整合性を検証するAppleのサービスです。起動時に、アプリケーションはAppleサーバーからアテステーションチャレンジを受け取り、Secure Enclaveの秘密鍵で署名し、自身のサーバーに送信します。デバイスがジェイルブレイクされている場合、Secure Enclaveはアテステーション失敗を返し、保護された機能へのアクセスをブロックします。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。