mirror of
https://github.com/qtmleap/revkit.git
synced 2026-09-29 06:21:51 +02:00
116 lines
3.9 KiB
Markdown
116 lines
3.9 KiB
Markdown
# PXA ESN — LLM 向けリファレンス
|
|
|
|
## PXA ESN とは
|
|
|
|
Netflix Android アプリがサーバーから取得するデバイス識別子。ローカル生成の Base ESN (PRV) に対し、サーバーが fingerprint を付与して発行する。API リクエストの `X-Netflix.esn` ヘッダーで使用される。
|
|
|
|
## 取得プロトコル
|
|
|
|
- **経路:** MSL (Message Security Layer) over HTTPS
|
|
- **エンドポイント:** `/getProxyEsn`
|
|
- **取得方法:** Cookie ではなく、MSL レスポンスの JSON ボディで返される
|
|
|
|
### リクエスト
|
|
|
|
```json
|
|
{"url": "/getProxyEsn"}
|
|
```
|
|
|
|
MSL VolleyRequest のヘッダーに `router: getProxyEsn` が設定される。HTTP レベルのヘッダーは MSL 暗号化されるため外部からは見えない。
|
|
|
|
### レスポンス
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"version": 2,
|
|
"serverTime": 1773478742949,
|
|
"result": {
|
|
"esn": "NFANDROID1-PXA-P-L3-GOOGLPIXEL=4A==5G=-22594-02028KVLM5OU1MSB..."
|
|
},
|
|
"common": {},
|
|
"from": "playapi"
|
|
}
|
|
```
|
|
|
|
PXA ESN は `result.esn` に格納されている。
|
|
|
|
## 有効期限
|
|
|
|
- 設定値: `EsnHendrixConfig.refreshProxyEsnTimeInMs = 0`
|
|
- TTL が 0 のため **無期限キャッシュ**
|
|
- 一度取得したら SharedPreferences に永続化され、以下の場合のみ再取得:
|
|
- 初回インストール
|
|
- アプリデータクリア
|
|
- SharedPreferences の消失
|
|
- `masterTokenSerialNumber` の変更
|
|
|
|
## fingerprint の特性
|
|
|
|
- サーバー側で生成され、ローカルでは再現不可
|
|
- 同一デバイスでも取得ごとに異なる fingerprint が返される
|
|
- 実測で 3 回取得し、毎回異なることを確認
|
|
|
|
## ESN 構造
|
|
|
|
```
|
|
NFANDROID1-PXA-P-L3-GOOGLPIXEL=4A==5G=-22594-0202{fingerprint}
|
|
```
|
|
|
|
| セグメント | 値 | 説明 |
|
|
|---|---|---|
|
|
| Platform | `NFANDROID1-` | Android プレフィックス |
|
|
| Type | `PXA` | Proxy (サーバー発行) |
|
|
| Category | `P` | Phone (T=Tablet, B=TV, C=ChromeOS, E=Display) |
|
|
| Security | `L3` | Widevine Security Level |
|
|
| Model | `GOOGLPIXEL=4A==5G=` | サニタイズ済みデバイスモデル |
|
|
| systemId | `22594` | Widevine systemId |
|
|
| fingerprint | `0202...` | サーバー発行 (毎回異なる) |
|
|
|
|
## 保存先
|
|
|
|
SharedPreferences に 2 つのキーで保存:
|
|
|
|
| キー | 型 | 内容 |
|
|
|---|---|---|
|
|
| `nf_drm_esn` | String | PXA ESN 文字列 |
|
|
| `nf_drm_proxy_esn` | String (JSON) | `{"esn":"...","ts":epoch_ms,"sn":serial_number}` |
|
|
|
|
## 使用箇所
|
|
|
|
| ヘッダー | 使用先 |
|
|
|---|---|
|
|
| `X-Netflix.esn` | GraphQL / Cronet リクエスト |
|
|
| `X-Netflix-ProxyEsn` | WebSocket / MSL リクエスト |
|
|
|
|
## コードパス
|
|
|
|
```
|
|
WidevineEntityAuthEsnProviderImpl.c(serialNumber) -- 再取得が必要か判定
|
|
→ ProxyEsnMslRequest -- MSL リクエスト送信
|
|
→ body: {"url": "/getProxyEsn"}
|
|
→ Netflix playapi サーバー
|
|
← onSuccess(JSONObject) -- レスポンス受信
|
|
→ result.esn を抽出
|
|
→ ProxyEsn.onKnown(serialNumber, esn) -- SharedPreferences に保存
|
|
```
|
|
|
|
## 関連クラス
|
|
|
|
| クラス | ファイルパス | 役割 |
|
|
|---|---|---|
|
|
| `ProxyEsnMslRequest` | `mslagent/impl/ProxyEsnMslRequest.java` | MSL リクエスト発行・レスポンス処理 |
|
|
| `ProxyEsn` | `esn/impl/ProxyEsn.java` | キャッシュ管理・永続化 |
|
|
| `WidevineEntityAuthEsnProviderImpl` | `esn/impl/WidevineEntityAuthEsnProviderImpl.java` | ESN 統合管理 |
|
|
| `EsnHendrixConfig` (`o.fkQ`) | `o/C13212fkQ.java` | TTL 設定 (`refreshProxyEsnTimeInMs`) |
|
|
|
|
## キャプチャ方法
|
|
|
|
`hook_msl.js` を使用。`ProxyEsn.$init` で expired フラグを強制 true にすることで、キャッシュの有無に関係なく `getProxyEsn` を発火させられる。
|
|
|
|
```bash
|
|
./run_android.sh hook_msl.js
|
|
```
|
|
|
|
出力イベント: `proxyEsn.forceExpired`, `proxyEsn.request`, `proxyEsn.requestHeaders`, `proxyEsn.response`, `proxyEsn.onKnown`, `proxyEsn.error`
|