Files
live-hub-py/docs/HUYA_WEB_FIELD_TRACE.md
T

152 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 虎牙网页设备字段溯源(2026-09-01 浏览器实测实证)
## 一、来源判定方法(有头 Chrome + 打点探针)
- `Page.addScriptToEvaluateOnNewDocument` 拦截 `Document.prototype.cookie` setter
记录每条写入的 值/时间/调用栈(栈中含脚本 URL + 行号)。
- `Network.responseReceivedExtraInfo` 捕获服务端 **Set-Cookie** 头。
- 全新 profile,导航 www.huya.com + 直播间页,静置后导出。
## 二、决定性结论:哪些字段服务端下发,哪些浏览器生成
### ✅ 服务端 Set-Cookie 下发(仅 5 个)
| 字段 | 实测 |
| --- | --- |
| `PHPSESSID` | l.web.huya.com / l.huya.com |
| `udb_deviceid` | udblgn.huya.com`w_` + 19 位数字,匿名设备) |
| `sdid` | udblgn.huya.com`0UnHUgv0_qmfD4KA...` 设备指纹) |
| `v` | 页面版本 |
| `HMACCOUNT` | 百度统计 |
### ✅ 浏览器脚本 document.cookie 写入(铁证:调用栈)
| 字段 | 生成脚本 | 关键位置 |
| --- | --- | --- |
| `guid` | `a.msstatic.com/huya/main3/npm..pnpm-d84ecac2_850fe68b.js` `Object.setCookie` | 写入 5 次;**位置 12-16 固定 `966a`(跨会话一致)** |
| `_qimei_fingerprint` | `staticfile.qq.com/qimei/qimeisdk-web/0.6.3/index.js` | 写入 1 次 |
| `udb_passdata` | `a.msstatic.com/huya/main3/common/headerfunction_d8b3ad0c.js` `writeCookie` | 固定值 3 |
| `__yasmid` / `__yamid_tt1` | 页面脚本 | 同值 17 位小数 |
### ⚠️ 浏览器生成但**非 document.cookie 写入**(走 Cookie Store API / localStorage 同步等)
| 字段 | 证据 | 说明 |
| --- | --- | --- |
| `__yamid_new` | 88 条写入中无此 key,但最终 cookie 有值 | **CBCC 前缀 + 递增种子**(见下) |
| `game_did` | 同上 | 30-35 位字母数字 |
| `_qimei_uuid42` | 同上 | `1a` 前缀 + 32hex UUID 结构 + 10hex |
## 三、设备字段结构规律(真实样本)
### guid = `0a` + 10hex + `956a`/`966a` + 16hex —— 有固定段,非纯随机
```
0a7dfa5fc9ee966aab02a2eaa3ea1de1 ← live 窗口
0a7dfaa2d7af966a2101f370f470ce50 ← round2 fresh
0a7de265986f956a24015b505c504506 ← reqable 8.31
0a89d5f6614b956aa6020bbc0cbc18fe ← cahrles 8.31
```
位置 12-16 恒为 `956a` / `966a`(产品段?),8.31 为 `956a`、我们机器为 `966a` ——
可能与 SDK/页面版本有关。
### __yamid_new = `CBCC`/`CBCB` + 种子6hex + 计数4hex + `0001` + 随机12hex
```
CBCC 6479D9 B000 0001 52EC19001D2017B2 ← live 窗口
CBCC 551C11 E000 0001 783D8F5530901BCC ← round2 fresh
CBCC 06ECB5 0000 0001 B63016D6162BC990 ← reqable 8.31
```
- 前缀 `CBCC`/`CBCB` 恒定(产品标识)
- 种子段递增且与 `_yasids`rootsid**同源共享时钟**
`yamid=CBCC6479D9B0...``rootsid=CBCC647A8A20...`(同会话,种子差 0xB1≈177
- `0001` 固定,尾部大段随机
### _qimei_uuid42 = `1a` + 40hex32hex UUID 结构 + 10hex 附加)
```
1a81f140c08100b89fb1be450f640501568684b2ea ← reqable 8.31
1a901123a1f10045427c1c73420287f44f49d11b45 ← round2 fresh
1a901171b051007527940c2acef15dcd2342b6ff ← live 窗口
```
首字节 `1a` 恒定;前 32 hex 符合 RFC 4122 UUID 布局(8-4-4-4-12)。
### _qimei_fingerprint = SpookyHashV2(canvas指纹, 31) 32hex
qimeisdk-web 0.6.3 源码已定位:
- 画 "qimei" 文本(Times New Roman 11pt+ `#f60` 背景 + 透明度矩形
- 三圆叠加(`#f2f`/`#2ff`/`#ff2` 40 半径)+ 环形 `#f9c` evenodd
- `canvas.toDataURL()`**SpookyHashV2**r 函数,64 位,seed=31)→ 32hex
## 四、溯源结论与建议
| 字段 | 来源 | 风控关联性 | 建议 |
| --- | --- | --- | --- |
| `guid` | 浏览器脚本(有固定段 `0a..966a`| 高(设备与会话绑定) | **必须按结构仿造或复用 wsLaunch 会话值**;随机纯 hex 与真实结构不符 |
| `__yamid_new` | 浏览器脚本(CBCC 前缀+种子)| 高(与 rootsid 同源)| 需要前缀 `CBCC` + 种子同步生成逻辑 |
| `_qimei_uuid42` | QIMEI SDK 0.6.3`1a` 前缀)| 中 | 前缀 `1a` + UUID 布局 |
| `_qimei_fingerprint` | QIMEI SDK 0.6.3 SpookyHashV2 | 中 | **算法已完全逆向**(源码在手),可精确复现 |
| `game_did` | 浏览器脚本 | 中 | 长度需对齐(35 变体含 `-`|
| 统计字段(SoundValue 等)| 页面脚本 | 低 | 随机 OK |
**下一步选项**
1. `_qimei_fingerprint` 直接用 SpookyHashV2 实现(canvas 指纹用标准值替代)
2. `guid` 采样更多样本确认固定段后按 `0a` + 结构仿造
3. `__yamid_new` 需找到生成它的具体脚本(非 document.cookie 写入,可能在
ubtk/埋点脚本里)做种子同步
## 六、核心字段生成算法逆向结果(2026-09-01 晚,浏览器实测 + 源码定位)
### ✅ __yamid_new = room_normal.js generate32UUID-v1 风格,已 Python 复刻验证)
```js
// a.msstatic.com/huya/main3/app/room_normal_55c7cc4f.js
function u(e){var t="__yamid_new",n=getCookieVal(t);if(n)return n;n=e||d.generate32();...writeCookie(t,n,...)}
d.generate32(){
c = new Date().getTime() - new Date(1582,10,15,0,0,0,0).getTime(); // 本地时区 epoch
return generateBits(c,0,31) // time_low 8hex
+ generateBits(c,32,47) // time_mid 4hex
+ generateBits(c,48,59)+"1" // time_hi+版本位
+ generateBits(rand(4095),0,7) + generateBits(rand(4095),0,7)
+ generateBits(rand(8191),0,7)+... 48位随机node;
}
```
- 浏览器实测 epochGMT+8: `-12216643543000`Python 复刻 12hex 时间戳段与浏览器**逐位一致**
- **`CBCC` 前缀是时间戳自然结果**(1582-epoch 当前值的高位),非固定魔数;随生成时刻缓慢递增
- `_yasids`(rootsid)同源同刻生成(浏览器实测 yamid=`CBCC653E4B...` / rootsid=`CBCC647A8A...` 共享种子时钟)
### ✅ game_did = vplayerUI.js 35 位随机(已复刻)
```js
// a.msstatic.com/huya/h5player/room/2608311423/vplayerUI.js
B = (t=35) => { const e="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
for(i="";i.length<t;) i += e.charAt(parseInt(Math.random()*(e.length-1))); return i }
```
- **长度 35**(旧随机 30 位是错的);字符集 64 去掉末尾 `_`63 选 1
- cookie 名 `game_did`,无 cookie 时生成并写入
### ⚠️ _qimei_uuid42 结构已定,算法待深挖
- cookie 值:首字节 `1a` 固定 + 40hexlocalStorage 是 44hexcookie 为截断子串)
- 由 qimeisdk-web 0.6.3 内部 VM 生成(`_qimei_ssid`/`_qimei_last_get_id_time_<16hex>` 同源)
- 当前实现对齐结构(1a 前缀 + 42hex 随机化),精确算法待继续
### ⚠️ _qimei_fingerprint = SpookyHashV2(canvas指纹,31),待 canvas 复现
- SDK 0.6.3 内置 x64hash128 与 canvas 指纹逻辑(文本+三圆+环形)
- 设备稳定(同 profile 跨会话不变);当前实现随机 32hex 格式对齐
- 复现需在真实环境执行 canvasheadless 下 canvas 指纹固定,可抽取一次固化为常量)
### 已修正生成器(core/huya/web_cookie_fields.py, commit 待定)
- `__yamid_new``_yamid_new_generate32()`UUID-v1 时间戳复刻)
- `game_did``_game_did_generate()`35 位 63 字符集)
- `_yasids` → 与 `__yamid_new` 同源同刻生成
- `_qimei_uuid42``1a` 前缀 + 42hex
- `guid`(无会话值回退)→ `0a` + 10hex + `966a` + 16hex 结构
## 七、逆向生成器端到端验证(2026-09-01 晚,账号 18397482576 重新登录后)
新版生成器(web_cookie_fields.py commit 8fef04d)产出字段:
- guid=`0a43b01a366c966a7fe26a281e1d3c88`0a 前缀 + 966a 固定段)
- __yamid_new=`CBCC65D6C5200001F176114BCF181E25`UUIDv1 时间戳)
- _qimei_uuid42=`1a552b4b...`1a 前缀)
- game_did=35 位
- _yasids 与 yamid 同源(CBCC65D6C5 前缀一致)
webActUI 全链路 status=200
1. checkUserBindGameAccount → 和平精英/痛仰之吻
2. getUserScore → gain=5580 available=280
3. getActPrizeList → 29 商品
4. **scoreExchangePrize → status=200 真实兑换成功**
(荣耀勋章礼包(小)20 分,订单 sOrderId_2203_12855_1199667330433_...
5. getUserPrizeRecords → 4 条
↑ 之前 getConfig 超时是旧 cookie 过期(id58 已清空),非生成器问题。