虎牙App密码登录: 逆向WUP协议并实现纯Python登录编码器

- hook WUP序列化层抓取TLS加密前明文,确认密码登录走
  servant=huyaudbwebui / func=hypasswordLogin (msgType=0x1001)
- 逆向JCE RequestPacket帧格式(1015字节TAF二进制),定稿三层结构:
  WUP header(tag1-10) -> sBuffer Map -> _wup_data业务struct
- 澄清两个疑点字节: 0x66/0x7d 是TAF字段头(非分隔符)
- 实现 tools/huya_wup_encoder.py,逐字节复现金标准
- 实测纯Python动态构造登录成功(返回uid+token),TLS指纹不阻断
- userAction随机坐标/时间戳同样通过,内置make_user_action辅助函数
- 新增证据金标准 + 协议文档
This commit is contained in:
yml2213
2026-08-25 02:59:20 +08:00
parent 06a0a1e7d3
commit ff99c036f8
14 changed files with 2185 additions and 0 deletions
@@ -0,0 +1,131 @@
# 虎牙 App 密码登录协议 — Frida 抓包实证
> 状态:**密码登录完整链路已抓包实证**
> 方法:spawn + libmsaoaidsec 绕过 + hook sendMsg/jbyteArray2str/str2jbyteArrayTLS 加密前的明文层)
> 证据文件:`/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/evidence/derived/huya-wup-plain.jsonl`
> Java 反编译:`/tmp/hy_jadx5/sources/com/huyaudbunify/`
---
## 一、密码登录请求(msgType = 0x1001 = 4097
`MsgLogin.mMsgId = 4097 (0x1001)`Java 层 `HuyaAuth.login()``sendMessage(4097, json)` → native `sendMsg(JNIEnv, jclass, jlong, jbyteArray)`
**请求 JSON**TLS 加密前明文,抓包实证):
```json
{
"bizAppids": [],
"isAuthLogin": false,
"lgnExtParam": {},
"name": "hy_300023887",
"password": "772ed992b0e161276f44ec63671e60155c506294",
"userAction": "{\"curl\":\"登录页\",\"furl\":\"我的\",\"latitude\":\"-1.0\",\"longitude\":\"-1.0\",\"ssid\":\"\",\"user_action\":[{\"id\":\"24\",\"time\":\"1787593636012\",\"x\":\"253\",\"y\":\"1573\"},...]}"
}
```
| 字段 | 值/规则 | 说明 |
|---|---|---|
| `name` | `"hy_" + 虎牙号` | 虎牙号 = 纯数字账号 |
| `password` | **标准 SHA1(明文密码) hex,无盐** | 40 字符小写 hex |
| `isAuthLogin` | false | 普通密码登录 |
| `bizAppids` | [] | 目标业务 appId 列表(空=主 app |
| `lgnExtParam` | {} | 扩展参数 |
| `userAction` | 风控行为 JSON | 点击轨迹、时间戳、坐标、curl/furl、经纬度 |
**密码哈希**(用户确认 + 抓包实证):
```
password = sha1(明文密码).hexdigest()
例如 sha1("某密码") = "772ed992b0e161276f44ec63671e60155c506294"
```
> 无盐、无 HMAC、无 RSA,就是裸 SHA1。
---
## 二、登录响应(msgType=0x1001 返回)
```json
{
"lastLgnTime": 1787593640035,
"token": "9QDzAAEDAAAAb2W4URcBAAABAGNI4jSgAQQANTAwOCgAMDJkZjM5ODc5NzQzMmVhZGVmY2MxMjc2NzExOWFkNWU4MDk5OTM4OQQANTAwOKIAAhKJiMHWd/m1LAKSxxpg1cjDxJEIG+ooj8BGSC5NBXb23Trpcz85MOqpZxhLmSeQ9c2MGzBk0oU4iR2PR0Ak6/t50Ej9sdzHjDLa2wcDiRofNyEZzuU1KcIQqrGDwwwfouEwuagTPI0ZrP5vAFJe8uccW5BKRVoqDDsXc09nIW7HX5Yp+9cT0nr8t/8+/3IdTXhFOZYmDN6gHaQI+ToQivXIAAAAAA==",
"tokenType": 2,
"uid": 1199666914671
}
```
| 字段 | 说明 |
|---|---|
| `token` | Base64,内含 TAF 二进制(`9QDzAAED...` 头),是后续凭据登录/接口调用的 token |
| `tokenType` | 2(密码登录产生的 token 类型) |
| `uid` | 1199666914671(该账号 uid |
| `lastLgnTime` | 上次登录时间戳(ms |
---
## 三、完整登录调用链(Java → native → 网络)
```
Java: HuyaAuth.login(name, password, isAuthLogin, bizAppids, callback)
└─ MsgLogin (mMsgId=4097=0x1001)
└─ ReqLogin.toString() → JSON(含 SHA1 密码)
└─ HuyaAuthMgr.sendMessage(4097, jsonBytes)
└─ HuyaAuthCore.sendMsg(jlong, byte[]) [native JNI]
└─ sendMsg(JNIEnv, jclass, jlong msgType, jbyteArray)
└─ jbyteArray2str → 明文 JSON
└─ UdbHandlerMgr.getPlatFormMsgHandler() 处理
└─ TAF/WUP 包装(servant + func
└─ TLS (libhycrypto 自带 BoringSSL)
└─ 目标: udblgn.huya.com / udb3lgn.huya.com (443)
```
**关键符号地址**libudbauthunify.so):
| 函数 | 地址 | 作用 |
|---|---|---|
| `sendMsg` | 0x26244c | Java→native 消息入口(msgType + jbyteArray |
| `jbyteArray2str` | 0x262b00 | jbyteArray→std::string(请求明文) |
| `str2jbyteArray` | 0x262be8 | std::string→jbyteArray(响应明文) |
| `hyudb_otp_encrypt` | 0x32fa24 | OTP/dckey 加密(XXTEA+AES |
---
## 四、msgType 观察(本次抓包 305 事件)
| msgType | 次数 | 含义 |
|---|---|---|
| `0xb000003` | 92 | getLoginData(读取登录态/token),高频轮询 |
| `0xb000021` | 4 | setDeviceInfohdid + safedeviceid |
| **`0x1001` (4097)** | 1 | **密码登录**MsgLogin |
| `0xb000001` | 1 | 登录后 getLoginData |
| `0xb000024` | 1 | 登录后获取数据 |
| `0xb000013` | 1 | getConfigTAF 二进制,servant=mobileuif |
---
## 五、与 OTP 加密链的关系
密码登录时序(抓包时间线):
```
1787593639831 sendMsg msgType=0x1001 ← 密码登录 JSON 提交
1787593639988 crypto-otp b=2 ← 紧接着触发 OTP/dckey 加密(AESkeyMgr b=2
1787593639996 sendMsg msgType=0xb000001 ← 登录成功后的凭据流程
```
即:**密码登录本身用 SHA1 密码 + WUP 明文 JSON;登录成功后,native 层用 OTP 加密链(XXTEA+AES)生成 dckey 凭据,供后续业务接口(token/cred)使用**。
之前破解的 OTP 加密链(`tools/huya_app_crypto.py`)对应的是**登录后的凭据续期/设备绑定**,不是密码本身。
---
## 六、servant / URL
- 密码登录 CGI`/{servantName}/hypasswordLogin`
- URL`https://udblgn.huya.com/open/hy/passwordLogin`(国内版)
- servant 名运行时传入,登录类走 `huyaudb`/`huyaudbwebui`
- 设备信息:`getCgi()``/{servantName}/setDeviceInfo`hdid + safedeviceid
---
## 七、待确认项(剩余,影响较小)
1. **userAction 是否必填/可复用**:风控行为采集(点击轨迹),批量登录时能否固定/复用同一份,还是每次都要真实模拟。
2. **登录接口是否校验 OTP dckey**:密码登录请求本身是否需要先拿到 dckey(本次抓包 OTP 在密码登录之后触发,说明密码登录可能不依赖 dckey)。
3. **token 的 TAF 结构解析**:响应 token 的 Base64 内是 TAF 二进制(`9QDzAAED...`),需解析出 uid/appid/时间戳等字段。