Files
live-hub-py/docs/虎牙证书算法闭环-差分实证.md
yml2213 a0ba2fe020 feat(huya): 证书算法完全闭环 - 差分法证明标准AES-128-ECB并复现铸证
- NativeFunction直调差分: FIPS-197 KAT逐位一致, UdbAESUtil无魔改
- 证书 = b64([0x0C][key_idx][AES128-ECB(key16, zeropad(P1_187B))])
- P1结构: [010400][5008][u16+20B随机][u16+40B指纹hex][u16+114B hyCred]
- 密钥: rodata默认三条(AESkeyMgr id=3/4/5) + 服务端下发会话钥(key_idx区分)
- tools/cert_forge.py 重铸证书与活体密文 FULL MATCH
2026-08-25 15:21:11 +08:00

87 lines
4.2 KiB
Markdown
Raw Permalink 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.
# 虎牙 udb 登录证书(biz_token)算法 — 差分法完全闭环(2026-08-25
> 状态:**加密算法 100% 复原,Python 重铸与活体密文逐位一致**
> 方法:静态反汇编(objdump) + Frida NativeFunction 直调差分 + C1 构造器抓钥
> 工具:`tools/udb_aes.py`(参考实现) `tools/cert_forge.py`(解析/铸造) —— 自检均通过
> 证据:`evidence/aes_diff.json` `evidence/cert_keycap.json`
---
## 一、结论一句话
```
证书 = base64( [0x0C][key_idx][ AES-128-ECB(key16, zeropad(P1_187B)) ] )
```
- **UdbAESUtil 是教科书级标准 AES-128-ECB**,无任何魔改:
- FIPS-197 KAT 直调逐位一致:`Cipher(00112233..ff, key000102..0f) = 69c4e0d8...`
- KeyExpansion 标准展开,轮密钥按「字表转置」存储(176B @ this+0x208
- 对象布局:+0x00 vptr | +0x08 S-box拷贝 | +0x108 InvS-box拷贝 | +0x208 轮密钥
- ZeroPadding:补 `\0` 到 16 倍数,**不追加整块**(187→192)。
- 此前"标准解密对不上"的原因:**拿错了密钥**(真钥不是 HuyaUdb 主密钥字符串本身)。
## 二、P1 明文结构(187B,两份活体样本逐字段对齐)
| 字段 | 长度 | 说明 |
|---|---|---|
| `[01][04][00]` | 3 | 固定头 |
| `"5008"` | 4 | appId |
| `[u16_le=20]` + rnd | 22 | 每次生成随机(os.urandom 即可) |
| `[u16_le=40]` + fp | 42 | 设备指纹 ASCII hex `02df39879743...`,设备绑定跨会话不变 |
| `[u16_le=114]` + cred | 116 | **hyCred 二进制**=base64(udb_cred) 解码),账号绑定 |
## 三、密钥机制(AESkeyMgr
- rodata `0x1bc810` 内置三条 24 字符默认密钥(`AESkeyMgr::C2` 注册 id=3/4/5):
```
4VYcPdvKKqjBHZtCmbroRXHk ← 本次活体实测在用(encode_aes 收整条,C1 只取前16字节)
xXEDWqiKLGwEZ6HubEiswCqK
3FMHubdKosFrhmXNLHTNHZwe
```
- 证书第二字节 = **key_idx**:今日样本 `0x20` ↔ 上表第一条;更早样本 `0x50`
用三条默认钥均解不开 ⇒ 存在**服务端下发的会话密钥**(对应 dckey/check 的
NEWKEY/key_id 老线索)。服务端按 idx 选钥解密。
- ⚠️ `HuyaUdb1928374650qwertyuiop` 是本地登录态文件加密用的主密钥,
**不是**证书密钥(此前误判的根源)。
## 四、调用链(函数地址级)
```
HandlerGetH5InfoEx::onHandler @0x38d548
└ BusinessCfg::getOtp @0x2689f4
└ gen_biz_token(BIZTOKEN,...) @0x3307e4 # P1 组装(enpack_header/body,cred_packls,xxtea)
└ encode_aes(P1, key24str, out) @0x330218 # out.assign(常量); C1(key.data())
├ UdbAESUtil::C1(uchar* key16) @0x24eb08 # ★抓钥点: 每次必经
└ UdbAESUtil::encrypt @0x250038 # 补零逐块 -> _encrypt@0x24f9f0 -> Cipher@0x24f314(10轮)
└ CBase64::Encode
```
全部符号在 `.dynsym` 导出(binary stripped 但 dynsym 完整),可直接 NativeFunction。
## 五、复现步骤
```bash
# 1) 差分验证(直调 C1/Cipher, FIPS-197 KAT)
/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/.venv/bin/python scripts/hook_aes_diff.py
# 2) 抓当前会话证书密钥 + 完整 wupData
/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/.venv/bin/python scripts/hook_cert_keycap.py
# 3) 离线重铸自检
.venv/bin/python tools/cert_forge.py # FULL MATCH: True
# 4) 参考实现自检
.venv/bin/python tools/udb_aes.py
```
frida 注意事项:手机端 frida-server 14.2.18,必须用 RE 项目 venv(frida==14.2.18)
时序不可变:force-stop → spawn挂起 → bypass_msaoaid_maps_art_callsite +
mask_frida_maps_only 双脚本 → resume → 10s → patch_guard → 业务脚本。
直调 libc++ string 时**禁止让 push_back 触发 realloc**(会对 frida 缓冲区
operator delete 导致 abort——第一次闪退即此因,非反调试)。
## 六、剩余开放项
1. **key_idx↔密钥映射的服务端语义**:0x20/0x50 的生成规则、下发通道
dckey/check? 登录态 JSON?)、轮换周期。工程上可绕过:直接 hook C1 取当期钥。
2. **任意账号 hyCred 获取**(硬骨头②):APP WUP 密码登录已通,
待从登录态/HA.getCred 提取目标账号 114B cred 即可离线铸其证书。
3. 铸造证书的活体验证:新随机数重建证书 → bindQrLoginUser(下一步)。