arm64e上で手作りのMach-Oチェーン修正を介してdyldをPAC署名オラクルとして使用するPoC。制御されたPAC有効ポインタ書き込みと、iOSでのディスパッチコールバック実行を実現します。
dyld のページインリンクとチェイン修正機構を PAC 署名オラクルとして利用する、CVE-2026-20700 に関する制御された探索。
arm64e では、すべての関数ポインタがハードウェア認証されます。ここでの目標は、dyld 自身の通常の修正メカニズムだけを使って、手動で作成した Mach-O を通じて dyld を誘導し、攻撃者が選んだスロットに PAC 有効なポインタを生成させられることを示すことです。
テスト環境: iPhone 14 (iOS 18.5, arm64e)
__DATA 内の選択したスロットに PAC 有効な関数ポインタを書き込む。fixupPage64 での決定論的クラッシュ — 不正な page_start / next 値により dyld がページ境界を超え、分岐到達可能性を証明する。dispatch_source_t タイマーハンドラとして登録され、イベントループを通じて自然に呼び出される。PoC コードからの直接呼び出しは行わない。dyld-signing-oracle-poc/
├── Makefile ← パイプライン全体を統括
├── src/
│ └── launcher.c ← iOS ランチャー(2 スレッド + ディスパッチチェインクローズ)
├── generators/
│ ├── gen_exports.py ← exports.c を生成(N 個のダミーシンボル)
│ ├── gen_client.py ← client.c を生成(N 個のインポート、dyld ゲート負荷)
│ └── gen_malformed_dylib.py ← libmalformed.dylib を生成(手動作成 Mach-O)
├── tools/
│ ├── scan_pointers.py ← Mach-O のポインタセクションを W/R に分類
│ └── inspect_fixups.py ← LC_DYLD_CHAINED_FIXUPS ヘッダを解析
└── blog/
├── it/
│ └── dyld-signing-oracle.md ← イタリア語の完全解説
└── en/
└── dyld-signing-oracle.md ← 英語の完全解説
| ファイル | 生成元 |
|---|---|
exports.c | generators/gen_exports.py + Makefile のセンチネルシンボル |
client.c | generators/gen_client.py |
libmalformed.dylib | generators/gen_malformed_dylib.py |
libexports.dylib | clang で exports.c から |
libclient.dylib | clang で client.c から |
PoCApp | clang で src/launcher.c から |
PoCApp.ipa | Makefile の package ステップ |
xcrun --sdk iphoneos --show-sdk-path)# デフォルトのフルビルド(arm64、99k シンボル)
make
# 反復開発用の高速ビルド
make SYMBOLS=10000
# fixupPage64 での決定論的クラッシュ(分岐到達可能性の証明)
make stress
# 安定したイメージ内書き込み-書き込み(write-what-where)
make exploit
# dyld が PAC 有効ポインタを書き込み → ディスパッチが自然に呼び出す
make chain_close
# 生成されたチェイン修正ブロブのレイアウトを検証
make verify
# libmalformed.dylib の LC_DYLD_CHAINED_FIXUPS ヘッダを解析
make inspect
# コンパイル済みバイナリ全体のポインタセクション(GOT/非遅延)をスキャン
make scan
| 変数 | デフォルト | 説明 |
|---|---|---|
SYMBOLS | 99000 | libclient 内のバインドターゲット数(< 100k で 26.3 以前のゲート、< 64k で 26.3 以降) |
STACK_KB | 128 | ワーカースレッドのスタックサイズ(KB) |
BURN_KB | 0 | dlopen 前に消費するスタック KB(0 は自動) |
MARGIN_KB | 24 | 自動バーンの余裕値 |
ARM64E | 0 | DYLD_CHAINED_PTR_ARM64E_USERLAND24 形式を使用 |
MALFORM_PAGEIN | 0 | 不正なページインチェーンを有効化 |
MALFORM_TARGET_OFFSET | — | __DATA 内のターゲットオフセット(例: 0x10) |
CHAIN_CLOSE | 0 | 2 番目のスロットを _attacker_hook に設定し、ディスパッチデモを有効化 |
# アドホック署名(Sideloadly)
make chain_close
# PoCApp.ipa を Sideloadly にドラッグ
# 正規証明書
make resign IDENTITY="iPhone Developer: ..." PROFILE=embedded.mobileprovision
# ログ監視
idevicesyslog | grep "POC"
PoCApp 内での実行時ロード順:
libexports.dylib — 最初にロードされる(RTLD_GLOBAL)。後続の dlopen に対して write_target_value と attacker_hook を提供する。libclient.dylib — スレッド B(128KB スタック)によってロードされる。約 99k のバインドターゲットが dyld のページインリンクゲートに負荷をかける。libmalformed.dylib — スレッド A によってロードされる。手動で作成されたチェイン修正チェーンにより、dyld が _write_target_value(およびオプションで _attacker_hook)を __DATA+0x10 / +0x20 に解決して書き込む。chain_close モードでは、メインスレッドが __DATA+0x20 を dispatch_source_t タイマーハンドラとして登録する。イベントループが 1 秒後にそのハンドラを呼び出し、PoC コードからの直接呼び出しは行われない。イタリア語と英語の完全な技術解説。PAC ハードウェアの仕組み、ポインタ生成器としての dyld、チェイン修正エンコーディングの基礎、ページインリンクゲートの仕組み、Mach-O エンジニアリングの落とし穴(sizeofcmds、セクション数、ストライド)、カナリア検証によるデータレイアウト、99k シンボルゲート、クラッシュによる到達可能性の証明、安定したイメージ内プリミティブ、arm64e 署名オラクルの概念、ディスパッチタイマーのチェインクローズを網羅。