Files
revkit/docs/spec/unknown_values_report.md
tkgstratorandClaude Opus 4.6 b8b27b1ef9 feat(re): appboot署名検証鍵を抽出し未知の値の調査レポートを作成
- kAppBootKey (RSA-4096) / kAppBootEccKey (P-256) / kSharkBootKey を
  NFWebCrypto.framework から静的抽出し constants.py に追加
- DH prime p は MslClient.framework @ 0x001265a0 で確認済み
- apphmac / devicetoken / device_key_data はランタイム生成と判明
- docs/spec/unknown_values_report.md に全調査結果を記載

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 08:43:08 +00:00

144 lines
5.9 KiB
Markdown

# Unknown Values Investigation Report
Date: 2026-04-09
appboot → MSL 認証の Python 実装に必要な未知の値の調査結果。
---
## 1. 抽出済み (バイナリにハードコード)
### kAppBootKey — RSA-4096 SPKI/DER (550B)
| 項目 | 値 |
|------|-----|
| バイナリ | NFWebCrypto.framework |
| オフセット | `0x0020cd31` (`__TEXT.__cstring`) |
| 格納形式 | Base64 エンコード (736 chars) |
| 用途 | appboot レスポンスの RSASSA-PKCS1-v1_5 署名検証 |
| ハンドル | `"ABKP"` |
| Python 定数 | `constants.IOS_APPBOOT_RSA_KEY_DER` |
### kAppBootEccKey — ECDSA P-256 SPKI/DER (91B)
| 項目 | 値 |
|------|-----|
| バイナリ | NFWebCrypto.framework |
| オフセット | `0x0020d10c` (`__TEXT.__cstring`) |
| 格納形式 | Base64 エンコード (124 chars) |
| 用途 | appboot レスポンスの ECDSA 署名検証 |
| ハンドル | `"ABECCKP"` |
| Python 定数 | `constants.IOS_APPBOOT_ECC_KEY_DER` |
### kSharkBootKey (prod) — ECDSA P-256 SPKI/DER (91B)
| 項目 | 値 |
|------|-----|
| バイナリ | NFWebCrypto.framework |
| オフセット | `0x0020d08f` |
| 用途 | Shark boot 署名検証 |
| Python 定数 | `constants.IOS_SHARKBOOT_KEY_DER` |
### DH Prime p — 1024-bit (128B)
| 項目 | 値 |
|------|-----|
| バイナリ | **MslClient.framework** (NFWebCrypto ではない) |
| オフセット | `0x001265a0` (`__TEXT.__const`) |
| ロード関数 | `IosAdhKeyx::dhKeyGen` @ vaddr `0x00079d20` |
| Generator g | `5` (vaddr `0x00079d98`) |
| Python 定数 | `constants.IOS_DH_P`, `constants.IOS_DH_G` |
```
9694e9d8 d93a5ac7 4c509b4b bce85e92
132cd19c ce477d1a 7e47d527 d9ec2915
15f0b8b3 e1eaed50 06e1b1b9 1ea25b91
a01b10e2 e834b8d6 60b2e321 ad644ce1
a83b328d 9014ee7e 16f1e44f fe89579a
c3ee47d6 68b6b766 87c2fe90 a35b5e60
28fd04ef ea882373 ecf60ba2 f637e4cd
aa1b6089 d6c0b561 a8e520e7 96de27df
```
### PSK / KDF Nonce (既知、再確認)
| 値 | オフセット | サイズ |
|----|-----------|--------|
| PSK: `027617984f6227539a630b897c017d69` | NFWebCrypto @ `0x1ac8f5` | 16B |
| Nonce: `809f82a7addf548d3ea9dd067ff9bb91` | NFWebCrypto @ `0x1ac905` | 16B |
---
## 2. ランタイム生成 (ハードコードされていない)
### apphmac (32B, HMAC-SHA256)
**結論: バイナリに固定鍵なし。ランタイム導出。**
NFWebCrypto の全 6 HMAC call site を静的解析した結果、すべてランタイム導出の鍵を使用:
| Call site | 関数 | 鍵ソース |
|-----------|------|----------|
| `0x000101a0` | `nflxDhDerive` | `SHA384(DH private key)` (48B) |
| `0x0000e640` | `hmacSign` | `AppleNativeKey::getBytes()` |
| `0x00011990` | `HKDF-Extract` | caller 引数 |
| `0x000119b8` | `HKDF-Expand` | 前段の PRK |
| `0x0001aa4c` | HMAC wrapper (SHA256) | caller 引数 |
| `0x0001aac8` | HMAC wrapper (SHA384) | caller 引数 |
**キャプチャ方法**: `hook_entityauth_capture.js` で HMAC 出力 32B をフィルタ。入力 216B (devicetoken サイズ) の HMAC コールが `apphmac = HMAC(PSK, devicetoken)` の有力候補。
### devicetoken (216B, protobuf)
**結論: NRM (Netflix Registration Management) サービスからランタイム取得。**
- **Nbp.framework**: `-[MslRegistration getDeviceTokensWithCallback:]` @ `0x0005d5c0`
→ `getNRMCookieWithESN:callback:` → NRM サービスへ HTTP リクエスト
→ レスポンスの `tokens` プロパティ → `initWithGUID:tokens:` で credentials 構築
- **MslClient.framework**: `IosMGKAuthenticationData` コンストラクタ @ `0x0000d45c` の第5引数
- protobuf 構造: field 2 = 188B opaque payload, field 3 = type enum (6), field 4 = 14B nested proto
- セッション間で安定 (241 セッション中 41 種のユニーク値)
**キャプチャ方法**: `hook_entityauth_capture.js` で Nbp シンボルをフック、または `IosMGKAuthenticationData` コンストラクタ引数をキャプチャ。
### device_key_data (~6,576B)
**結論: ランタイム組立の CBOR 構造体。単一の静的 blob ではない。**
`entity_auth_data` は以下の CBOR フィールドから組み立てられる:
**IosMGKAuthenticationData** (@ `0x000103bc`):
| フィールド | オフセット | 内容 |
|-----------|-----------|------|
| `identity` | +0x98 | ESN 文字列 |
| `appid` | +0xb0 | アプリケーション ID |
| `appkeyversion` | +0xc8 | 整数 |
| `apphmac` | +0xd0 | Base64 HMAC |
| `devicetoken` | +0xe8 | NRM トークン |
**FpsMgkAppIdAuthData** (@ `0x00029bec`): `devtype`, `mgkid`, `keyrequest`, `appid`, `appkeyversion`, `apphmac`, `devicetoken`
6,576B は TFIT-WB-AES 暗号化された MGK 鍵素材 (`mgkid`/`keyrequest`) を含む CBOR エンコーディング全体のサイズ。
**キャプチャ方法**: `hook_entityauth_capture.js` で NSData/sqlite フック、または appboot リクエスト全体をバイナリキャプチャして CBOR デコード。
---
## 3. まとめ
### Python 実装で必要な値の状態
| 値 | 状態 | Python で再現可能か |
|----|------|-------------------|
| kAppBootKey (RSA-4096) | **抽出済み** | Yes — `constants.IOS_APPBOOT_RSA_KEY_DER` |
| kAppBootEccKey (P-256) | **抽出済み** | Yes — `constants.IOS_APPBOOT_ECC_KEY_DER` |
| DH prime p | **抽出済み** | Yes — `constants.IOS_DH_P` |
| DH generator g | **抽出済み** | Yes — `constants.IOS_DH_G = 5` |
| PSK / Nonce | **抽出済み** | Yes — `constants.IOS_KDF_PSK` / `IOS_KDF_NONCE` |
| Device header (128B) | **抽出済み** | Yes — `constants.IOS_KEY336_DEVICE_HEADER` |
| TFIT tables | **抽出済み** | Yes — `emulate_tfit.py` で Unicorn エミュレーション |
| apphmac | **要ランタイムキャプチャ** | No — Frida で鍵と入力を特定後、Python 再現の可能性あり |
| devicetoken | **要ランタイムキャプチャ** | No — NRM サービス応答。キャプチャ値をパラメータとして渡す |
| device_key_data | **要ランタイムキャプチャ** | 部分的 — CBOR 構造は既知、MGK 部分は TFIT で再現可能 |