test(huya): 风控场景/代理/扫码闭环探针与逆向文档

- probe_huya_login_scene: 各 appId/UA 组合的风控策略探测
- probe_huya_proxy: 走代理源对比直连的风控策略
- probe_huya_qr_bind: 扫码登录闭环(getQrId->scanQrPicNotify->
  bindQrLoginUser->tryQrLogin), 实测出有效web会话; 含wupData
  结构地图与证书定位实验结论(见 docs/虎牙扫码登录闭环逆向.md)
This commit is contained in:
yml2213
2026-08-25 11:51:01 +08:00
parent 705c51bf48
commit 9aea9851bd
4 changed files with 632 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
# 虎牙扫码登录闭环逆向(2026-08-25)
数据来源:用户抓包 `~/Desktop/抓包/hy/8.24`(手机扫码登录-1 / -手机端2 / -pc端2.har
探针脚本:`scripts/probe_huya_qr_bind.py`
## 一、协议链(qrLgn JSON 协议,纯 HTTPS,无原生 WUP 套接字)
```
PC角色(appId=5002, sign=1ce3bf68..., version=2.6, context WB-xxx)
① POST /qrLgn/getQrId uri=70001 -> data.qrId
⑥ POST /qrLgn/tryQrLogin uri=70003 轮询 stage: 0->1->2
stage=2 时返回 uid + biztoken(344B) => 构造 cookie 即登录成功
手机角色(appId=5131, sign=0ba67962ab9e12387648efeae2750777, version=2.5, context H5-xxx)
② GET https://aq.huya.com/r/confirm.html?k=<qrId>&id=5002 (App WebView 内)
③ POST /qrLgn/scanQrPicNotify uri=70005 data={qrId,wupData,...} -> stage=1 + 登录方信息
④ POST /qrLgn/bindQrLoginUser uri=70007 data={qrId,wupData,...} -> stage=2
```
注:`-1.har` 里还有旧版协议 `udbrtt.huya.com/auth/qr/notify|verify`confirm 页 s/confirm.html),
新流程走 qrLgn 直连,二者 wupData 结构相同。
## 二、web 会话构造(已验证 rc=0)
```python
cookies = {
'udb_uid': str(uid), 'yyuid': str(uid),
'udb_passport': 'hy_xxx', 'username': 'hy_xxx',
'udb_version': '1.0', 'udb_biztoken': <tryQrLogin 返回的 344B>,
'udb_origin': '1', 'udb_status': '1',
}
# 验证: udbreg /web/v2/modifyPswByCheck 无cookie/垃圾token -> rc=2005 USER_NO_LOGIN
# 扫码会话最小cookie -> rc=0 ★(不需要 udb_cred/udb_deviceid/udb_other
```
## 三、wupData 结构地图(998Bbase64 后随请求提交)
| offset | 内容 | 服务端校验 |
|---|---|---|
| 15 | servant `huyaudbwebui` func `default` | - |
| 70-273 | meta JSON `{associationId:184549392,id:184549392,session,traceId,type:2,uid:0,...}` | ❌ session/traceId 乱改仍通过 |
| 274 | `"5008"` | - |
| 282-463 | blob1 181B(与 safedeviceid 同前缀 `PQwemAN9...`) | ❌ 整段替换金标准 safedeviceid 仍通过 |
| 473-506 | hdid `ed0db8334cadd236c00cadf7e11ab5a5`=金标准) | 未单独测 |
| 508-686 | 设备信息 13.4.22 / 1.0.801386 / 127.0.0.1 / xiaomi / M2102J2SC+指纹hash / android / 1080x2120 / device_id hash | 未单独测 |
| **701-962** | **尾部 blob 261B —— 登录证书** | ✅ 破坏→`rc=40020 CERT_BIZERR_CREATE_ERROR`;清空→`rc=100 SYS_ERROR`;缺失→`rc=101 PARAM_ERROR` |
## 四、关键实验结论
1. **身份完全由尾部证书 blob 决定**
- 无 cookie / 垃圾 cookie / 真·APP WUP token 当 `udb_biztoken` → 全部无视,
绑定结果始终 = 抓包手机上登录的账号(hy_300023887 uid=1199666914671)。
- 先用 WUP 把 hy_299961311 登到同一设备身份再扫码 → 绑定仍是 hy_300023887
(服务端不做"设备最新登录"映射)。
2. **整个 web 登录不需要密码**getQrId → bind(wupData) → tryQrLogin 三步即出会话。
3. **证书可复用、可并发**:同一 wupData 已复用 10+ 次(跨 ~1h),5 路并发 2s 全成功。
4. APP WUP 密码登录(tools/huya_wup_encoder.py)对任意账号可用,
其响应中的 token(346B) 与 web biztoken(344B) 格式同族(解码后均以 `01 00` 开头),
但**不能**直接互换使用。
## 五、剩余缺口:每账号一张证书
尾部 blob 是与"App 内已登录会话"绑定的证书,生成逻辑在 App 原生 SDK
confirm.html 会先调 `udbdf.huya.com/dckey/check`,请求体本身加密)。
可行路径:
- **A. 每账号一次种子采集**:手机登录某号 → 触发一次任意 udb H5 confirm 流程 →
mitmproxy 抓 `bindQrLoginUser` 的 wupData 存库 → 该账号永久全自动。
(批量成本 = 每号一次人工,之后零人工)
- **B. 逆向证书生成算法**dckey/check 协议 + 原生加密,周期长不确定。
- 待观察:证书有效期(当前样本 >1h 仍有效)。
## 六、复现命令
```bash
.venv/bin/python scripts/probe_huya_qr_bind.py <账号> <密码> \
--har "/Users/yml/Desktop/抓包/hy/8.24/手机扫码登录-手机端2.har"
# 成功记录: evidence/qr_login_success.json(含有效 biztoken,已 gitignore
```