feat(huya): nonce生成机制完全破解 - 任意账号零设备出完整CK闭环
动态hook实锤(scripts/hook_nonce_chain.py): rnd = XXTEA(pack(st) + pack(counter|st<<16), key=MD5hex(uid_str + k1)[:16]) - st=毫秒时间戳, counter同st内递增 - k1=设备常量865a4924...(不随账号变, evidence/nonce_k1.json) - Python复刻(tools/nonce_forge.py)对设备两轮rnd逐字节MATCH 推翻v2误判(X2'nonce账号绑定令牌'实为nonce内编码uid): - 换账号用目标uid重算nonce而非复用旧nonce! - 纯随机nonce必40020因解不出合法st/counter结构 实测: 同账号+跨账号(hy_300024708从未设备登录)本地nonce铸证bind均通过, full_web_cookie/full_auto_safe 任意账号密码->全套cookie(udb_cred/udb_biztoken)
This commit is contained in:
@@ -351,3 +351,58 @@ X2根因分析: 信封内uid仅t3一处(BE@688, metaJSON里uid=0/associationId=0
|
||||
|
||||
safe_auth闭环(app_login_flow.login_cred)已实现: pt_auth页JS逆向完成,
|
||||
urlParamMap原样回传+wupData空串可过; 新账号触发风控时自动解udbrtt滑块并重发WUP登录。
|
||||
|
||||
## ★★★★ nonce 生成机制完全破解 + 任意账号零设备闭环(2026-08-26凌晨)
|
||||
|
||||
### 动态hook实锤(scripts/hook_nonce_chain.py + /tmp/opencode/nonce_chain.json)
|
||||
|
||||
在真机上对 getQUrlData→getOtpEx→gen_biz_token→xxtea 全链路 hook, 拿到运行时实参:
|
||||
|
||||
```
|
||||
serviceTime = 当前毫秒时间戳 (0x1a039b1fc81 ≈ 1.787e12)
|
||||
nonce_next = counter | (serviceTime << 16) # counter 同st内递增, 从0开始
|
||||
xxtea key输入 = uid_str + k1 # k1 = BusinessCfg::this+0x10
|
||||
xxtea key = MD5hex(uid_str + k1)[:16] # 注意取hex字符串前16字符!
|
||||
xxtea data = pack(serviceTime) + pack(nonce_next) # 各8B小端
|
||||
xxtea 输出 = ceil(len/4)+1 words, 末尾word存原长度 → 16B输入=20B输出
|
||||
```
|
||||
|
||||
**rnd = XXTEA(pack(st) + pack(counter|st<<16), key=MD5hex(uid+k1)[:16])**
|
||||
|
||||
### 关键发现
|
||||
|
||||
1. **k1 是设备级常量**: 对 uid=1199666914671 和 uid=1199666911746 两次调用,
|
||||
k1 均为 `865a4924a40897ac1fcfe6b4c2cbb0e3`, 不随账号变化!
|
||||
(证据: /tmp/opencode/k1_multi.json, gbt_in.k1 两次同值)
|
||||
2. **nonce 完全本地可算**: serviceTime=本地时钟, counter从0开始, k1固定
|
||||
→ 任意账号用 目标uid+k1 即可离线铸造合法 nonce!
|
||||
3. **Python 复刻逐字节一致**: tools/nonce_forge.py 对设备两轮 rnd
|
||||
(80dd1dfa... / 0ba8f8b7...) 完全 MATCH。
|
||||
|
||||
### 终极验证: 纯协议任意账号 bind + cookie 全通!
|
||||
|
||||
| 实验 | 结果 |
|
||||
|---|---|
|
||||
| 同账号本地nonce铸证 bind (hy_300023887) | ✅ ok:true biztoken344B |
|
||||
| **跨账号**本地nonce铸证+patch uid (hy_300024708→uid1199666911746) | ✅ ok:true biztoken344B |
|
||||
| **新账号从未设备登录** 全链路: 密码→cred→本地nonce→bind→cookie | ✅ 全套cookie(udb_cred/udb_biztoken...) |
|
||||
|
||||
### 修正早前错误结论(X2"nonce账号绑定令牌"实为误判)
|
||||
|
||||
X2(换uid+换cred+复用旧nonce)→40020 的真正原因:
|
||||
**nonce 内编码了 uid**(通过 MD5(uid+k1) 派生key), 服务端用 t3.uid 重新派生key解密 nonce,
|
||||
旧nonce(绑旧uid)配新uid 自然解不开 → 40020。
|
||||
**正确做法**: 换账号时用【目标uid】重新计算 nonce, 而非复用旧nonce!
|
||||
→ 这也解释了为什么"纯随机nonce必40020": 随机值无法用uid+k1解出合法st/counter结构。
|
||||
|
||||
### 新的工程铁律(v3, 推翻v2的"每号设备首登一次")
|
||||
|
||||
1. nonce = XXTEA(pack(st)+pack(counter|st<<16), key=MD5hex(uid_str+k1)[:16]), 本地可算;
|
||||
2. k1 = 设备常量(865a4924...), 一次采集永久可用(evidence/nonce_k1.json);
|
||||
3. 任意账号: 密码→登录取cred→目标uid+k1重算nonce→铸证→bind→cookie, 全程零设备!
|
||||
4. 信封本身(TAF帧)可长期复用/补丁(uid/cert), 不依赖账号。
|
||||
|
||||
### 资产更新
|
||||
- tools/nonce_forge.py: 本地nonce生成器(XXTEA+MD5, 自检对设备实采)
|
||||
- scripts/probe_nonce_bind.py: 本地nonce bind验证脚本(同/跨账号)
|
||||
- evidence/nonce_k1.json: k1设备常量证据
|
||||
|
||||
Reference in New Issue
Block a user