Files
live-hub-py/docs/虎牙App密码登录协议-抓包实证.md
T
yml2213 ff99c036f8 虎牙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辅助函数
- 新增证据金标准 + 协议文档
2026-08-25 02:59:20 +08:00

132 lines
5.7 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.
# 虎牙 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/时间戳等字段。