QEMU で iPhone をエミュレートするという記事を見かけて整理した前提知識メモ
1. はじめに
Hacker News をぼんやり眺めていたときに、面白そうな記事を見かけた。
Apple の SecureROM(ブートROM)に修正不可能な脆弱性が存在し、これを悪用して iOS デバイスのブートチェーンをハイジャックする手法があることは知っていたが、具体的な実装やメカニズムについてはあまり詳しくなかった。
上述の記事内容を理解するには、まず checkm8, checkra1n, PongoOS についての基本的な理解が必要になる。
そのため、まずはそれらを理解するところから始める。
2. iOSブートシーケンスの全体像と詳細
2.1. iOSブートシーケンスの全体像
iPhoneの電源ボタンを押してから画面が表示されるまでの間に、数多くの複雑なプロセスが背後で実行される。この起動シーケンスを理解することは、iOS のセキュリティモデルを把握する上では欠かせない。
ということで、まずはiOSのブートシーケンス全体像を見ておく。
iOSデバイスは基本的に3つの起動パスを持っている。
-
通常起動
BootROM → LLB → iBoot → Kernelcache (Root=/) -
リカバリー
BootROM → iBSS → iBEC → Kernelcache (Root=recovery) -
アップグレード
BootROM → LLB → iBoot → Kernelcache (Root=upgrade)
https://yungraj.com/checkra1n/
起動プロセスは常にBootROM(SecureROM)から始まる。これはデバイスの製造時にチップに焼き付けられた変更不可能なコード。
そこからの経路は状況によって分岐する。
各ステージではセキュリティ検証が行われ、次のステージのコード署名を確認してから実行権限を渡す。この連続的な検証は「信頼の連鎖」(Chain of Trust)と呼ばれる。
この連鎖のいずれかの段階で検証が失敗すると、通常はリカバリーモードへ移行する。これにより不正なコードの実行を防止している。重要なのは、この連鎖が物理的に変更不可能なBootROMから始まることで、理論上はシステム全体の整合性を保証している。
ただし、BootROMに脆弱性があれば、この連鎖全体が崩れる可能性がある。これがcheckm8のような低レベルの脆弱性が特に注目される理由である。
2.2. 各ブートパスの詳細
2.2.1. 通常起動パス
https://yungraj.com/checkra1n/
通常の起動シーケンスは最も一般的なパスで、ユーザーが日常的に経験するものである。
BootROMの主な目的は、不揮発性メモリから第一段階のブートローダーを安全に読み込み、起動すること。上記の図でいえば、最初にNANDフラッシュメモリからLLB(Low Level Bootloader)をロードする。LLBはハードウェアの初期化と検証を行い、次にiBoot(第二段階ブートローダー)をロードする。iBoot自体も正常に動作することを確認した後、NVRAM内の「boot-command」変数を確認する。
この変数がデフォルト値「fsboot」の場合(または設定されていない場合)、iBootはメインのiOSカーネルキャッシュをロードし、ルートファイルシステムをマウントして通常の起動を続ける。
通常起動の特徴は次の通り。
- ユーザーデータにフルアクセス
- すべてのシステム機能の利用可能
- 最小限の初期化プロセス
重要なのは、各段階で署名検証が行われること。たとえば、iBootはカーネルキャッシュのApple署名を検証し、改ざんされていないことを確認してからロードする。これにより、不正に改変されたシステムコンポーネントの実行を防止している。
2.2.2. リカバリーパス
https://yungraj.com/checkra1n/
通常の起動が不可能な場合や、ユーザーが特定のボタン操作(例:電源ボタンとホームボタンの同時押し)を行った場合、デバイスはリカバリーモードに入る。
リカバリーモードではBootROMが異なるパスを選択し、iBSS(iBoot Single Stage)と呼ばれる特別なコンポーネントをロードする。iBSSはiBEC(iBoot Epoch Change)をロードする。
iBECはリカバリーやアップグレードの際に使用されるiBootの軽量版で、通常のiBootよりも機能が制限されている。iBECはリカバリーモード用のカーネルをロードし、リカバリーRAMディスクをマウントする。このRAMディスクには最小限のシステムと復元に必要なツールが含まれている。
リカバリーモードの特徴は次の通り。
- iTunes/Finderとの接続要求
- 自動的に最新のiOSとファームウェアをダウンロード
- ユーザーデータへのアクセス制限
- 工場出荷状態への復元機能
リカバリーRAMディスクは重要な役割を持つ。このRAMディスクは既存のデータを消去し、デバイスを工場出荷時の状態にリセットする機能を提供する。図にもあるように、「Recovery ramdisk triggers obliteration of /var (reset to factory defaults)」とある通りだ。
2.2.3. アップグレードパス
https://yungraj.com/checkra1n/
アップグレードパスは、特にOver-The-Air(OTA)アップデートの際に使用される。この場合、NVRAM内の「boot-command」変数が「upgrade」に設定される。
通常起動と同様に、BootROMからLLB、そしてiBootまでは同じパスをたどる。しかし、iBootが「boot-command」変数を確認した際に「upgrade」値を検出すると、アップグレード用のカーネルキャッシュをロードし、アップグレード用のRAMディスクをマウントする。
アップグレードパスの特徴は次の通り。
- ユーザーデータの保存(通常)
- システムファイルの更新に特化
特筆すべきは、アップグレードRAMディスクの役割だ。図にもあるように「Upgrade ramdisk preserves contents of /var, reformats /」という特性がある。つまり、ユーザーデータ(/var)は保持しながら、システムパーティション(/)のみを再フォーマットする。これにより、ユーザーデータを失うことなくOSのアップグレードが可能になる。
2.3. ブートチェーンの各コンポーネント
https://www.iphone-ticker.de/apples-downgrade-verbot-ios-aktualisierungen-ohne-weg-zurueck-106365/
それぞれのコンポーネントがブートチェーン内で果たす役割と特性について見ていく。
2.3.1. SecureROM(BootROM)
BootROMはiOSセキュリティアーキテクチャの基盤となる最初のコードであり、次のような特性を持つ。
- シリコンに焼き付けられた読み取り専用メモリ(ROM)に格納
- 製造後は絶対に変更不可能
- サイズは約150KB程度と非常に小さい
- デバイス起動時に最初に実行されるコード
- 「信頼の連鎖」の開始点
BootROMの主な機能は次のステージ(通常はLLB)を検証してロードすることだ。また、デバイスの復旧のためのDFU(Device Firmware Update)モードもサポートしている。
DFUモードはBootROMに組み込まれた特別なモードで、デバイスが通常のブートプロセスを実行できない場合でも、USB経由でファームウェアを復元できるようにする。これはどうにもこうにもならないときの「最後の砦」として機能するが、同時にcheckm8のような脆弱性の標的にもなる。
2.3.2. LLB(Low Level Bootloader)
LLBは「第一段階ブートローダー」として機能し、次のような特性を持つ。
- NANDフラッシュからロードされる
- BootROMによって署名が検証される
- 主要なハードウェアの初期化を担当
- iBootをメモリ内に配置して検証する
図にもあるように「Low Level Boot Loader loaded from NAND, locates iBoot」がLLBの主な役割だ。LLBはiBootを見つけ、その署名を検証してロードする。署名検証に失敗すると、リカバリーモードに移行する。
2.3.3. iBoot
iBootはiOS起動プロセスの中心的な役割を担うブートローダーであり、次のような特性を持つ。
- LLBによってロードされる
- カーネルとデバイスツリーをロードして検証
- NVRAM変数の処理と起動モードの決定
- 「boot-command」変数に基づいて異なるブートパスを選択
iBootは重要なNVRAM変数「boot-command」を処理する。この変数の値により、通常起動(「fsboot」)、アップグレード(「upgrade」)などの異なるブートパスが選択される。図の右上にある通り、iBootはこの変数に基づいてカーネルキャッシュをロードする。
署名検証に失敗した場合や他のブートチェーン異常が検出された場合、iBootはリカバリーモードへの移行を開始する。これは図の中央にある「Invalid signatures or any boot chain abnormalities drop to recovery mode」に対応している。
2.3.4. iBSS/iBEC(リカバリーコンポーネント)
リカバリーモードでは、異なるコンポーネントが使用される。
- iBSS(iBoot Single Stage):リカバリーモード用の特別なローダー
- iBEC(iBoot Epoch Change):リカバリー用の軽量版iBoot
iBECは通常のiBootよりも機能が限定されているが、リカバリーカーネルとリカバリーRAMディスクをロードするのに十分な機能を持つ。図にあるように「iBoot Epoch Change loaded for recovery mode」として位置づけられている。
2.4. iOSセキュリティモデル
iOSのブートシーケンスを理解した上で、その背後にあるセキュリティモデルを確認する。
2.4.1. 署名検証
https://www.sentinelone.com/blog/checkm8-5-things-you-should-know-new-ios-boot-rom-exploit/
iOSのセキュリティの中心となるのが暗号署名による検証だ。ブートチェーンの各ステージでは、次のステージをロードする前に署名の検証が行われる。
- BootROMがLLBの署名を検証
- LLBがiBootの署名を検証
- iBootがカーネルキャッシュの署名を検証
- カーネルがシステムライブラリとアプリケーションの署名を検証
この連続的な検証により、「信頼の連鎖」が形成される。署名はRSA暗号とSHA-256ハッシュを組み合わせたもので、Appleの秘密鍵でのみ生成できる。
ブートシーケンス図の中央に示されている「Invalid signatures or any boot chain abnormalities drop to recovery mode」は、この署名検証が失敗した場合の挙動を表している。検証に失敗すると、デバイスはリカバリーモードに移行し、正規のファームウェアのインストールを促す。
2.4.2. KPP/KTRR/AMCC
カーネルはOSの中核であり、特別な保護が必要である。iOSには以下のようなカーネル保護メカニズムが実装されている。
2.4.2.1. KPP(Kernel Patch Protection)
iOS 9で導入されたKPPは、カーネルのコードセクションとデータ構造が実行時に改ざんされていないかを定期的にチェックする。カーネルの保護領域への変更が検出されると、システムを強制的に再起動させる。
2.4.2.2. KTRR(Kernel Text Readonly Region)
A10チップ以降で導入されたKTRRは、ハードウェアレベルでカーネルコード領域を読み取り専用として保護する。一度ロックされると、カーネルコードへの書き込みはハードウェアによって物理的に阻止される。
2.4.2.3. AMCC(Apple Memory Cache Controller)
A11チップ以降では、AMCCという専用のハードウェアコントローラが導入された。これはKTRRをさらに発展させたもので、DMA攻撃からも保護する。物理メモリへのアクセスを直接制御することで、周辺機器からの不正なメモリアクセスも防止する。
これらの保護機構は、ブートチェーンの後半(カーネルロード後)で有効になるが、ブートシーケンスの安全性に大きく依存している。つまり、BootROMが侵害されると、これらの保護も回避される可能性がある。
2.4.3. AMFI(Apple Mobile File Integrity)
AMFIはカーネル拡張機能で、実行時のコード署名検証を担当し、次のような特性を持つ。
- すべてのユーザーランドプロセスの署名を検証
- アプリのサンドボックスプロファイルを適用
- コード署名のエンタイトルメント(アクセス権)を検証
- 「トラストキャッシュ」を管理して署名検証のパフォーマンスを向上
AMFIは「トラストキャッシュ」と呼ばれるシステムも管理しており、署名検証済みのバイナリの情報をキャッシュしてパフォーマンスを向上させる。
AMFIはブートシーケンスの最終段階(カーネルロード後)で有効になるが、やはりブートチェーンの安全性に依存している。もし前段階が侵害されていれば、AMFIの保護も無効化される可能性がある。
2.4.4. セキュアエンクレーブ(SEP)
https://support.apple.com/en-uz/guide/security/sec59b0b31ff/web
A7チップ以降のiOSデバイスには、セキュアエンクレーブプロセッサ(SEP)が搭載されている。SEPは物理的に分離された専用のサブシステムで、生体認証データや暗号化キーなどの機密情報を処理する。
SEPの特性は次の通り。
- 独自のOS(SEPOS)を実行
- メインプロセッサとは物理的に分離
- 専用の暗号エンジンを搭載
- バイオメトリックデータ(Touch ID/Face ID)を処理
- Apple Payのセキュリティも担当
SEPはメインのブートチェーンとは独立したブートプロセスを持つ。メインのiOSシステムが侵害されても、SEP内のデータは保護されるよう設計されている。ただし、低レベルのハードウェア脆弱性(checkm8など)によって、SEPとメインプロセッサ間の通信を傍受できる可能性はある。これが、ブートROMレベルの脆弱性が特に危険視される理由の一つだ。
2.5. DFU(Device Firmware Update)モード
ブートプロセスがSecureROMを超えて続行できない状況が発生した場合、ブートチェーンは信頼されない。このような、デバイスが起動できない状況では、デバイスは復旧の最後の手段としてDFUモードにフォールバックします。
2.5.1. デバイスファームウェアアップデートの仕組み
DFUモードは、iOSデバイスの最後の救済手段と言える。
iOS自体が完全に停止している状態でもデバイスを復旧できる強力なメカニズムであり、このモードでは、IPSWファイルと呼ばれるiOSファームウェアパッケージを使用してデバイスを復元する。
また、リカバリーモードなどの通常の復旧方法は自動的に最新のiOSとファームウェアをインストールするが、DFUモードではユーザーが元に戻したいファームウェアを変更して選択することができる。
おおまかに次のような特性を持つ。
- SecureROMレベルで動作
- 画面は完全に黒い(何も表示されない)
- USB経由で接続されたコンピュータからの指示のみを待機(標準はiTunesを実行している別のデバイスへのUSB接続を必要)
- iTunes(または同様のソフトウェア)はIPSWファイルからiBSSを抽出し、DFUモードのデバイスにUSB経由で送信する
ブートシーケンス図の左下に示されているように「Device Firmware Update mode (through buttons) requests BSS from host」とあるように、DFUモードではホストコンピュータからiBSSをリクエストする。
2.5.2. USB制御転送プロトコル
DFUモードの中核となるのがUSB制御転送プロトコルである。この標準化されたUSBプロトコルはSecureROMに組み込まれている。
USB制御転送は主に3つのフェーズで構成される。
- セットアップステージ
8バイトのセットアップパケットが送信され、リクエストの種類や長さなどを指定 - データステージ
必要に応じてデータを転送 - ステータスステージ
転送の成功/失敗を伝える
DFUモードでは、このプロトコルを使用して新しいファームウェアイメージをデバイスにアップロードする。具体的には、iBSSをロードし、そこから通常のリカバリープロセスに進む。
checkm8エクスプロイトは、このUSB制御転送の処理に脆弱性を見つけ、それを悪用してSecureROMに任意のコードを実行させる。
2.5.3. DFUモードにおけるiBSSの起動プロセス
ここまでを踏まえて、DFUモード時のiBSSの起動プロセスは次のような流れになる。
- iPhoneがDFUモードでコンピュータに接続
- SecureROM(デバイスに内蔵されたブートROM)が最初に起動
- デバイスがDFUモードであることを検出すると、SecureROMはUSB経由でコンピュータからiBSSを受信する準備を整える
- iTunes(または同様のソフトウェア)はIPSWファイルからiBSSを抽出し、USBを介してデバイスに送信
- SecureROMは受信したiBSSの署名を検証する
- 署名が正当であれば、SecureROMはiBSSをメモリにロードし、実行を開始
- iBSSは次にロードするコンポーネント(通常はiBEC)の署名を検証
3. checkm8(チェックメイト)脆弱性の詳細
iOSのセキュリティモデルは長年にわたって堅牢なものだと考えられてきた。
特に低レベルのブートチェーンは、ほぼ侵入不可能だとみなされていた。しかし2019年9月、セキュリティ研究者のaxi0mXが「checkm8」と名付けた脆弱性を公開し、この常識を覆した。
3.1. 脆弱性の要点
checkm8はiOSセキュリティにおける基盤を揺るがした重大な脆弱性である。
その技術的な要点を掘り下げていく。
3.1.1. SecureROMにおけるUSB処理の脆弱性
checkm8の中核となる問題は、SecureROM(BootROM)のUSB制御転送処理コードにある。SecureROMはDFUモードでUSB経由のファームウェア更新をサポートしているが、この実装に欠陥があった。
具体的には、USBデータ転送を処理する際に、SecureROMがメモリバッファを適切に管理できていなかった。USBスタックは複雑で、特にDFU(Device Firmware Update)モードでのデータ転送においてセキュリティ上の問題があることが判明した。
この脆弱性はA5からA11までのチップ(iPhone 4SからiPhone X)に影響し、広範なiOSデバイスが対象となった。A12以降のチップではハードウェアレベルでUSB処理が改善され、この特定の脆弱性は修正されている。
3.1.2. Use-After-Free問題
checkm8は「Use-After-Free」(解放後使用)と呼ばれるメモリ管理の脆弱性の一種である。
この種の問題は以下のような流れで発生する。
- メモリ上にバッファが割り当てられる
- そのバッファが使用され、その後解放される
- バッファへのポインタがNULLに設定されない
- 解放されたメモリ領域が再利用される
- 古いポインタを通じてこのメモリに再度アクセスする
SecureROMのDFU実装では、USBコントロール転送中に一時バッファを割り当て、データ転送が完了すると解放する。しかし、DFU中止時に、このバッファへのポインタが適切にクリアされなかった。
この欠陥は、攻撃者がDFU転送を開始して中断した後、解放されたメモリ領域に新しいデータを書き込むことを可能にした。こうして、解放済みのメモリ領域を悪用できる状態が作られた。
3.1.3. Heap-Feng-Shuiによるメモリ操作
Use-After-Free脆弱性を実用的なエクスプロイトに変えるには、解放されたメモリ領域が予測可能な方法で再割り当てされるようにメモリヒープを操作する必要がある。これは「Heap-Feng-Shui」と呼ばれる技術である。
checkm8エクスプロイトでは、複数のUSB転送を特定のパターンで実行することでヒープを意図的に形成し、解放されたバッファが再割り当てされる場所を予測可能にする。この技術により、攻撃者は解放されたメモリ領域に自分のコードや重要なデータ構造を配置できる。
具体的には次のような手順を踏む。
- 特定のサイズのUSB転送を複数回要求し、ヒープに特定のパターンを作る
- 転送中のリクエストを中断して一時バッファを解放させる
- 新しい転送を開始し、解放されたバッファの位置に悪意あるデータを配置する
この精巧なヒープ操作により、攻撃者はSecureROMのコード実行フローを制御できるようになる。
3.1.4. なぜパッチを適用できないのか
checkm8脆弱性が特に重大なのは、対象となるSecureROMにパッチを適用できないという点だ。
その理由は単純明快である。
- SecureROM(BootROM)はシリコンに焼き付けられた読み取り専用メモリ(ROM)に格納されている
- 製造時に一度書き込まれると、物理的に変更不可能
- ソフトウェアアップデートでは修正できない
つまり、A5~A11チップを搭載したすべてのiOSデバイスは、生涯にわたってこの脆弱性を抱えることになる。Appleにできるのは、新世代のチップ(A12以降)でハードウェア設計を変更することだけだった。
この「修正不可能」という性質が、checkm8を「永久的なジェイルブレイク」として特別な存在にしている。対象デバイスはiOSのバージョンアップに関係なく、常にこの脆弱性を利用可能な状態にある。
3.2. エクスプロイトの仕組み
実際にcheckm8脆弱性がどのように悪用されるのか、その具体的なメカニズムを見る。
3.2.1. USB DFUモードの悪用方法
checkm8エクスプロイトはDFUモード中のSecureROMを標的にする。DFUモードに入るには通常、特定のボタン操作(電源ボタンとホームボタンなど)を行う。このモードはデバイスを復元するための「最後の砦」として設計されている。
エクスプロイトの第一歩はDFUモードに入ることだ。このモードでは、画面は黒く、デバイスはUSB経由での通信のみを受け付ける。SecureROMがメモリ上に読み込まれ、USBスタックが初期化される。
次に、攻撃者は特殊なUSBリクエストのシーケンスを送信する。
- 特定のサイズのDFU転送を開始
- 転送を中断して、バッファ解放を引き起こす
- 新しい転送を開始して解放されたメモリ位置にペイロードを配置
このリクエストシーケンスにより、SecureROMのメモリ管理に混乱が生じる。
3.2.2. メモリバッファ操作の詳細
checkm8エクスプロイトの核心部分は、USB DFUデータ転送時のバッファ操作である。
具体的には以下のような流れで進行する。
- DFU_DNLOADリクエストを送信して転送を開始
- 一時バッファがSecureROMによって割り当てられる
- データ転送中にDFU_ABORTコマンドを送信
- バッファが解放されるが、ポインタはNULLに設定されない
- 新しいDFU_DNLOADリクエストを送信
- 新しいデータが解放された同じメモリ位置に書き込まれる
この操作により、攻撃者は重要なメモリ構造(タスク管理など)を上書きできる。A8/A9チップには、DFU中止時にタスク構造体が漏洩する特定のバグがあり、これによりエクスプロイトの効果が増幅された。
より新しいデバイス(A10/A11)では、攻撃手法が若干異なるが、根本的な問題は同じだ。ヒープ形成(Heap-Feng-Shui)の技術を使って、解放されたバッファの再割り当てを制御する。
3.2.3. 実行フローのハイジャック
メモリバッファ操作に成功すると、攻撃者はSecureROMの実行フローを乗っ取ることができる。
これは主に以下の方法で行われる。
- タスク構造体や関数ポインタを上書き
- 例外ハンドラを改変
- スタックオーバーフローによるリターンアドレスの改ざん
一旦コード実行制御を獲得すると、攻撃者は自分のコード(シェルコード)をメモリ内の安全な場所にコピーし、そこに実行を移す。このコードは通常、後続のブートステージ(LLBやiBoot)をパッチするための準備を行う。
checkm8エクスプロイトのもう一つの重要な側面は、特定のレジスタやメモリマップを詳細に把握していることだ。エクスプロイトコードは、チップの種類によって微妙に異なるメモリレイアウトに対応する必要がある。
3.2.4. 対象デバイス(A5~A11チップ)
checkm8はA5からA11までのAppleプロセッサに影響する。
これは多数のiOSデバイスをカバーしている。
- iPhone: 4S, 5, 5c, 5s, 6, 6 Plus, 6s, 6s Plus, 7, 7 Plus, 8, 8 Plus, X
- iPad: 様々なモデル(第2世代から第7世代)
- iPod touch: 第5~第7世代
- Apple TV: 第3~第4世代
- Apple Watch: Series 1, 2, 3
これらのデバイスはすべて、チップ内のSecureROMに同様の脆弱性を持っている。しかし、チップによって具体的なメモリレイアウトやUSB処理のコードが異なるため、エクスプロイトはデバイスごとに調整が必要だった。
A12チップ以降(iPhone XS以降)では、SecureROMのUSB処理が改良され、この特定の脆弱性は存在しない。このため、最新のiOSデバイスは影響を受けない。
4. checkra1n(チェックレイン)とPongoOS
checkm8脆弱性の発見後、セキュリティ研究者たちはこれを実用的なツールへと発展させた。
その結果として生まれたのが「checkra1n」ジェイルブレイクツールと「PongoOS」プリブート環境である。
4.1. checkra1nの仕組み
checkra1nは、checkm8脆弱性を利用した完全なジェイルブレイクツールである。
単なる概念実証ではなく、一般ユーザーでも使えるように開発された。
4.1.1. checkm8脆弱性の実用的な活用
checkra1nの開発者たちは、checkm8脆弱性を次のように実用化した。
- 動作の安定化:研究段階のエクスプロイトは不安定なことが多いが、checkra1nは高い成功率で動作するよう最適化された
- 使いやすいインターフェース:コマンドラインツールからGUIアプリケーションへと発展
- デバイス検出の自動化:接続されたデバイスのチップ種類を自動判別
- DFUモード補助:ユーザーに適切なボタン操作を案内する機能
checkra1nの実行には、デバイスをDFUモードに入れる必要がある。ツールはUSB経由でcheckm8ペイロードを送信し、SecureROMを侵害する。
成功すると、カスタムブートローダー(PongoOS)がロードされ、さらに高度な操作が可能になる。checkra1nは「テザード」ジェイルブレイクであり、デバイスが再起動するたびに再適用する必要がある点には注意が必要。
4.1.2. ブートチェーンハイジャックの方法
checkra1nがSecureROMの制御を獲得すると、次はブートチェーン全体をハイジャックする。
この過程は以下のようなステップで行われる。
- SecureROMエクスプロイト成功後に初期の小さなペイロードを実行
- このペイロードによりPongoOSをメモリにロード
- PongoOSはiBootをパッチしてロード、または直接カーネルをパッチ
- パッチ適用済みiBootがカーネルをロード、またはPongoOSが直接パッチ済みカーネルをロード
- 特別なRAMディスクを使ってrwx(読み書き実行権限)のルートファイルシステムを作成
ハイジャックの重要な部分は、iBootに適用されるパッチだ。通常、iBootは次のステージのコード署名を検証するが、パッチによりこの検証がバイパスされる。これにより、未署名または改変されたカーネルを起動できるようになる。
ブートチェーンをハイジャックする過程で、checkra1nは動的パッチを適用する。つまり、チップの種類やiOSバージョンに応じてパッチ内容を調整する。これにより、様々なiOSバージョンに対応できる。
4.1.3. カーネルパッチの適用プロセス
ブートチェーンを確保した後、checkra1nはカーネルレベルの保護を無効化するためのパッチを適用する。
- KTRR/KPP/AMCCの無効化:カーネルの読み取り専用領域保護を解除
- AMFI(Apple Mobile File Integrity)の無効化:コード署名検証をバイパス
- サンドボックスの制限緩和:アプリが通常よりも多くの権限を得られるよう変更
- ダイナミックコードサイニングの許可:実行時にコードを生成・実行可能に
- dyldキャッシュの変更:システムライブラリに対するパッチの適用
これらのパッチは、カーネルのメモリ内イメージに直接適用される。つまり、ファイルシステム上のカーネルイメージは変更されない。これにより、再起動後も元のセキュリティ状態に戻せる。
カーネルパッチの適用には精密なアドレス計算が必要である。カーネルのレイアウトはiOSバージョンによって異なるため、checkra1nはパターンマッチングを使って適切なパッチポイントを特定している(らしい)。
4.1.4. ジェイルブレイクの完成
最終段階として、checkra1nはジェイルブレイク環境を設定する。
- /private/var/rootにブートストラップと呼ばれる特別なファイルシステムを作成
- 基本的なUnixツール(bash, ssh, sftp)をインストール
- Cybiaアプリストアなど、サードパーティアプリのインストールを可能にする
- Substrate/Substituteフレームワークをインストール(システムフックのため)
- tweakインジェクション機構(TweakLoader)をセットアップ
この段階で、ユーザーは通常禁止されている操作(ファイルシステムへのフルアクセス、システム設定の変更、非公式アプリのインストールなど)が可能になる。
ジェイルブレイクの「テザード」特性を克服するために、checkra1nはデーモンをインストールして再起動後も設定を保持できるようにする。ただし、完全なジェイルブレイク状態に戻すには、再度ツールを実行する必要がある。
4.2. PongoOSのアーキテクチャ
PongoOSはcheckra1nの重要なコンポーネントであり、独自の価値を持つプロジェクトでもある。
4.2.1. プリブート環境の概念
PongoOSは「プリブート環境」と呼ばれる、正規のiOS起動前に実行される軽量オペレーティングシステムである。これはLinuxの「初期RAMディスク」(initrd)やマイクロカーネルに似た概念だ。
PongoOSがブートROMからの制御を受け取ると、ハードウェアの初期化、メモリマップの設定、各種デバイスドライバのロードなどの基本的なタスクを実行する。これにより、iOSの正式なブートローダー(LLB/iBoot)に依存せずに、デバイスの基本機能を制御できる。
プリブート環境の主な利点は、iOSのセキュリティ機構が有効になる前に実行されることだ。これにより、通常はアクセスできないハードウェア機能や保護されたメモリ領域にアクセスできる。
4.2.2. 機能と役割
PongoOSは、単なるブートローダーではなく、多機能なプラットフォームとして設計されている。
- コマンドライン環境:対話的なシェルを提供し、様々なコマンドを実行可能
- デバイスドライバ:USB、UART、ディスプレイなどのハードウェアを制御
- パッチ適用フレームワーク:カーネルやシステムコンポーネントへのパッチを容易に
- モジュールシステム:追加機能を動的にロード可能
- デバッグサポート:低レベルのデバッグ機能を提供
PongoOSはUSB経由でホストコンピュータと通信できる。これにより、ユーザーはコマンドを送信したり、ファイルを転送したりできる。
さらに、PongoOSは様々なブートモードをサポートしている。iOSを通常起動したり、カスタムカーネルを起動したり、あるいは全く別のOSを起動したりする柔軟性を持つ。これが、iOSデバイス上でLinuxを実行するようなプロジェクトを可能にしている。
4.2.3. カーネルパッチファインダー(KPF)
カーネルパッチファインダー(KPF)モジュールは、異なるiOSバージョン間で動的にカーネルをパッチする機能を提供する。
- パターンマッチング:バイナリパターンを使ってカーネル内の重要な関数やデータ構造を特定
- シグネチャスキャン:命令シーケンスに基づいてパッチ適用ポイントを検索
- 自動アドレス解決:カーネルのメモリマップに関係なく、重要なシンボルを見つける
- バージョン非依存のパッチ:異なるiOSバージョンに対応するパッチを自動生成
KPFは、task_for_pid(0)、AMFI無効化、サンドボックス緩和など、ジェイルブレイクに必要な標準的なパッチをサポートしている。また、カスタムパッチの追加も可能。
このモジュールにより、iOSの新バージョンがリリースされるたびにパッチを書き直す必要がなくなった。KPFがカーネル構造を解析し、必要な変更を自動的に特定するためである。
4.2.4. 動的パッチ適用の技術
PongoOSが使用する動的パッチ技術は、標準的なバイナリパッチよりも高度である。
以下のような特徴がある。
- インメモリパッチング:ディスク上のファイルではなく、メモリ内のカーネルイメージを変更
- 関数レベルのフック:個別の命令だけでなく、関数全体の挙動を変更可能
- トランポリンコード:元の関数への参照を維持しながら新しいコードを挿入
- コンテキスト依存解析:周囲のコードコンテキストに基づいてパッチポイントを特定
この技術は特に、カーネルのメモリレイアウトがALSR(アドレス空間配置のランダム化)によって変わる場合に重要になる。動的パッチは、固定アドレスに依存せず、パターンと関係性に基づいてターゲットを見つける。
さらに、PongoOSはパッチの依存関係を管理する。例えば、あるパッチが別のパッチに依存している場合、適切な順序で適用される。
4.3. セキュリティ保護のバイパス
checkra1nとPongoOSは、iOSの多層防御セキュリティモデルの各層をバイパスするための手法を実装している。
4.3.1. 署名検証の回避
iOSの署名検証は、ブートチェーンの各ステージとユーザーランドアプリケーションの両方で行われる。
checkra1nはこれをバイパスするために、以下のような手法を使用する。
-
ブートチェーンレベル
- iBootの署名検証ルーチンにパッチを適用し、検証を常に成功として扱う
- 検証後のハッシュ比較操作をNOP命令で置き換える
-
カーネルレベル
- AMFIカーネル拡張にパッチを適用
- MAC(Mandatory Access Control)ポリシーの検証をバイパス
- コード署名エンフォースメントの無効化
-
ユーザーランドレベル
- dyldのコード署名チェックにパッチを適用
- ldidなどのツールを使って、実行時にバイナリに偽の署名を付与
これらの変更により、署名されていないコードや改変されたコードを実行できるようになる。特に重要なのは、AMFIへのパッチである。AMFIはアプリケーションやシステムバイナリの実行時署名検証を担当するため、これを無効化することで非公式アプリのインストールが可能になる。
4.3.2. KPP/KTRR/AMCCの無効化
Appleは、カーネルを保護するための複数のメカニズムを実装している。
checkra1nはこれらをバイパスするために、以下のような手法を使用する。
- KPP(Kernel Patch Protection)
- カーネルのロード前に保護対象ページを特定
- それらのページを別の非保護メモリ領域にコピー
- 元のページではなくコピーしたページを参照するようにポインタを変更
- KTRR(Kernel Text Readonly Region)
- ブート初期段階でKTRRレジスタが設定される前に介入
- KTRRレジスタを設定するMSR命令を無効化またはフック
- 保護対象領域を縮小または変更して、パッチ適用可能な領域を作成
- AMCC(Apple Memory Cache Controller)
- ハードウェアコントローラの初期化ルーチンをフック
- 保護設定を変更または無効化
- 物理メモリマッピングを操作して保護をバイパス
これらの保護機構はハードウェアレベルで実装されている場合が多く、バイパスは非常に複雑になる。checkra1nは、これらが初期化される前に介入することで、保護をバイパスしている。
4.3.3. PAC(ポインタ認証)対策
A12以降のチップでは、PAC(Pointer Authentication Codes)と呼ばれる機能が導入された。これはポインタを暗号的に署名し、不正な改ざんを防止する。
checkm8はA12以降には対応していないが、PAC対策の研究は続いている。
- パディングビットの操作:PACはポインタの未使用ビットを使用するため、これらのビットの処理を変更
- 署名検証のバイパス:PAC検証命令をフックまたは無効化
- 既知の有効な署名の再利用:正当なコンテキストで生成された署名を収集し再利用
近年の研究では、PAC実装にも脆弱性が見つかっている。この分野の研究は継続中である。
4.3.4. 永続的なアクセスの確立
ジェイルブレイクの完成度を高めるため、checkra1nは永続的なアクセスを確立する仕組みを提供している。
- デーモンインストール
- launchdの設定を変更し、起動時に特定のサービスを開始
- ジェイルブレイク環境を維持するためのバックグラウンドプロセスを設定
- ファイルシステム改変
- システムパーティションを読み書き可能としてリマウント
- 重要なシステムファイルをパッチまたは置換
- サードパーティアプリをインストールするための特別なディレクトリ構造を作成
- ブートストラップシステム
- 基本的なUnixツールとライブラリをインストール
- パッケージ管理システム(Cydia/Sileoなど)をセットアップ
- tweak(システム拡張)のロードシステムを確立
- コードインジェクション
- dylib(動的ライブラリ)をプロセスに挿入するフレームワークをインストール
- Substrate/Substituteなどのフックシステムを設定
- プロセス起動時に自動的にtweakをロードする仕組みを実装
これらの仕組みにより、デバイスが再起動しても、再度checkra1nを実行するだけでジェイルブレイク状態を復元できる。一部の設定や変更は永続的に保持される。
checkra1nジェイルブレイクは「テザード」であり、再起動のたびにツールを再実行する必要がある。これは、SecureROMの脆弱性を利用するという性質上、避けられない制限だ。しかし、一度ジェイルブレイクが完了すれば、ユーザーデータやインストールしたtweakは保持される。
さて、ここまでの概念を理解してようやく本記事を書くきっかけになったネタ記事の話題に入ることができる。記事内容を完全に理解するには、まだいくつかの(QEMU等の)知識が必要になるが、ここまでの内容を理解していれば、追加調査はそれほど難しくない(いや、嘘吐きました。結構難しい。コンパニオンQEMUでDFUモードのUSBプロトコルをエミュレーションして〜〜〜どうのこうのというiOSリストアは魔法にしか見えないだろう)。
その点まで含めて説明するとボリュームがとんでもないことになるので、ネタ記事内容はサマリ程度に留めておく。
5. eShardによるiOSエミュレーションの実現
eShardの技術者たちが実際にQEMUを用いてiOSのエミュレーションを実現するまでの道のりと、そこで直面した技術的課題を簡潔に追ってみる。
5.1. 主な技術的挑戦と解決方法
5.1.1. 基本的なエミュレーション環境の構築
エミュレーション環境の基盤としてTrungNguyen1909/qemu-t8030オープンソースプロジェクトを出発点に選択している。単に標準QEMUを使用するのではなく、すでにiPhoneハードウェア(特にt8030/A13チップ)向けに修正されたコードを土台にすることで、多くの基本的な問題を回避できるという利点がある。
このプロジェクトにより、すぐにシェルアクセスとSSH接続を確立することができた。具体的にはSystem/Library/xpc/launchd.plist
の修正によってシェルアクセスを可能にした。これは単純だが重要な一歩。
https://eshard.com/posts/emulating-ios-14-with-qemu
さらに注目すべきは、PongoOSとcheckra1n-kpfモジュールの活用である。通常の物理デバイスでは、USBを介してPongoOSをロードする(checkra1n による侵害)が、エミュレーション環境ではSRAMサイズを増加させ、より直接的な方法でPongoOSをロードする戦略を採用した。この方法により、カーネルに必要なパッチを動的に適用する仕組みを効率的に整備できている。
5.1.2. ディスプレイとグラフィックス処理の実現
グラフィックス処理は、特に困難な課題だったようだ。現代のiOSデバイスはMetalという独自のグラフィックスAPIに依存しており、これをエミュレートするのは非常に複雑だ。
https://eshard.com/posts/emulating-ios-14-with-qemu
研究チームは2つの主要なアプローチを検討している。
- ソフトウェアレンダリング:GPUをエミュレートする代わりに、CPUベースのレンダリングを使用
- Metal呼び出しの転送:実機iPhone/Macに処理を委譲する方法
https://eshard.com/posts/emulating-ios-14-with-qemu
最終的に、より実現可能なソフトウェアレンダリングアプローチを選択し、QuartzCoreフレームワークに適切なパッチを適用してこれを強制した。
さらに、IOSurfaceとIOMFB(IOフレームバッファ)のサポートを追加することで、基本的な画面表示を実現した。これにより、Appleロゴなど、最低限のUI表示が可能になった。
5.1.3. セキュリティ機能のバイパス
iOSの厳重なセキュリティ対策は、エミュレーションにおいて大きな障壁となった。
特に以下の2つが重要な課題だった。
-
アドレスのランダム化(ASLR)対策
通常、iOSはカーネルレベルからユーザースペースまで、あらゆるレベルでアドレス空間配置のランダム化を行う。これはデバッグを困難にする。
エミュレーション環境ではカーネルのランダム化を完全に無効化し、実行ファイルのランダム化を無効にするために_load_machfile関数にパッチを適用した。さらに、動的ライブラリ(dyldキャッシュ)のアドレス解決方法を構築することで、一貫したデバッグ環境を実現。 -
ポインタ認証(PAC)の問題解決
t8030チップ(iPhone 11)ではARM8.3+の機能である「ポインタ認証」が実装されており、これがエミュレーション環境で問題を引き起こした。PACは通常、ポインタの不正な改ざんを防ぐセキュリティ機能だが、QEMUでは完全にエミュレートするのが難しい。最終的にQEMU 8へのアップグレードと、コードベースの大規模な移植作業を行うことでこの問題を解決した。これはエミュレーションプロジェクト全体の中でも特に困難な課題だったようだ。
5.1.4. デバッグ環境の整備
実用的なエミュレーション環境には高度なデバッグ機能が不可欠だ。研究チームはGDBを使用してカーネルとユーザースペースの両方をデバッグできる環境を構築した。具体的には、ゲスト側にdebugserverを設置し、ホストからGDBで接続できるようにした。
システムログの取得も重要な課題だった。標準的なアプローチでは、lockdowndを介したペアリングが必要だが、これはSEP(Secure Enclave Processor)に依存しており、エミュレーション環境では利用できない。研究チームは、鍵ペアを手動で生成し、lockdowndにパッチを適用することでこの問題を解決した。これにより、idevicesyslogなどのツールを使用したシステムログの取得が可能になった。
さらに、メモリダンプ機能を実装し、グラフィックス処理などの問題を詳細に調査できる環境を整えた。
5.1.5. ユーザースペースのパッチ適用
iOS上のアプリケーションやシステムフレームワークを動作させるには、様々なユーザースペースコンポーネントにパッチを適用する必要があった。特に2GB以上の巨大なdyldキャッシュを効率的に修正する方法は重要な課題だった。
研究チームは、キャッシュ内の特定のフレームワークを位置を特定し、必要な修正を加えるためのツールを開発した。特に、SSHを介してファイル全体を転送することなく、ddコマンドを使って特定のオフセットに対する修正を適用する方法は賢明だった。
また、カーネルの署名チェックを無効化することで、修正されたdyldキャッシュがロードできるようにした。さらに、QuartzCoreなどの重要なフレームワークや、バックボードなどのシステムデーモンに必要なパッチを適用することで、グラフィカルUIの実現に近づいた。
5.2. 最終的な成果
長期間の試行錯誤の末、研究チームは以下のような成果を達成した。
-
PreBoardシステムプロセスの表示
通常はアップデート中などの特殊な状況でのみ表示されるPreBoardを起動させ、初期的なUI表示に成功した。 -
インタラクションの実現
VNCサーバーを追加することで、キーボード入力などのインタラクションが可能になった。 -
ハードウェア依存命令の対応
vImageフレームワークがApple Matrix Coprocessor(AMX)命令に依存する問題を解決し、ソフトウェア実装に置き換えた。 -
実用的なUI表示
最終的に、パスコード入力画面の表示に成功した。これは、基本的なiOSのUIスタックが機能していることを示す重要な成果だ。
これらの成果は、物理的なiOSデバイスを持たずに、iOSの内部動作を研究するための重要な一歩となる。エミュレーション環境は完璧ではないが、セキュリティ研究やソフトウェア解析において強力なツールとなり得る。
研究チームの成果は、iOSのような閉鎖的なシステムでも、創意工夫と粘り強い技術的アプローチによって理解を深められることを示している。今後もこのような取り組みが、モバイルOSのセキュリティ研究にとって重要な意味を持つだろう。
Discussion