Files
live-hub-py/docs/虎牙App密码登录-WUP明文抓包.md
T

310 lines
13 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 密码登录 — WUP 明文抓包实证(最终)
> 状态:**密码登录完整 WUP 请求已抓到(TLS 加密前明文)**
> 证据:`/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/evidence/derived/huya-wup-full3.jsonl`
> 方法:hook `createWupRequestData<AppLgnPasswordLoginReq>` onLeave 拿到序列化后的 WUP 字节
---
## 一、密码登录 WUP 请求(核心结论)
| 项 | 值 |
|---|---|
| **servant** | `huyaudbwebui` |
| **func** | `hypasswordLogin` |
| **协议** | WUP / TAF(JCE) 二进制序列化 |
| **msgType** | 4097 (0x1001) = `MsgLogin.mMsgId` |
| **请求大小** | 1356 字节 |
| **密码** | SHA1(明文) hex,无盐(`772ed992b0e161276f44ec63671e60155c506294` |
| **name** | 虎牙号为 `hy_<虎牙号>`;手机号登录时为 11 位手机号原值 |
---
## 二、WUP 帧完整结构(已 100% 逆向定稿)
> 金标准文件:`evidence/wup_passwordlogin_taf.bin`1015 字节 TAF 二进制)+ `evidence/wup_passwordlogin_base64.bin`1356 字节 base64,即 HTTP body
> HTTP`POST https://udblgn.huya.com/open/hy/passwordLogin``Content-Type: application/x-wup`
### 2.1 外层:WUP RequestPacket(标准 JCE/TAF 序列化)
```
[0:4] uint32 BE 总长 = 1015
JCE RequestPacket 字段(head = (tag<<4)|type:
tag1 iVersion = 3 (INT8: 10 03)
tag2 cPacketType = 0 (ZERO: 2c)
tag3 iMessageType = 0 (ZERO: 3c)
tag4 iRequestId = session(3251699) (INT32: 42 00 31 9d f3)
tag5 sServantName = "huyaudbwebui" (STR1: 56 0c + 12B)
tag6 sFuncName = "hypasswordLogin" (STR1: 66 0f + 15B)
tag7 sBuffer = MAP{...} (SIMPLE_LIST: 7d 00 01 03 c1 + 961B)
tag8 iTimeout = 0 (ZERO: 8c)
tag9 context = {} (空map) (MAP: 98 0c)
tag10 status = {} (空map) (MAP: a8 0c)
```
> 关键澄清:之前误认为 `'f'(0x66)` 和 `'}' (0x7d)` 是分隔符,实为 JCE 字段头:
> - `0x56` = 字段5(sServantName)+STRING1
> - `0x66` = 字段6(sFuncName)+STRING1
> - `0x7d` = 字段7(sBuffer)+SIMPLE_LIST
### 2.2 中层:sBuffer961 字节)是一个 MAP
```
MAP (2条目):
"_wup_data" → 915 字节 (内层登录请求 struct)
"wupudbrequest_v0" → 5 字节 = 02 00 31 9d f3 (版本2 + session INT32)
```
### 2.3 内层:_wup_data915 字节)登录请求 struct(完整字段映射)
```
_wup_data = STRUCT {
field0 = STRUCT { # 元数据+风控
tag0 = 0
tag1 = "1.0" # 协议版本
tag2 = 207B JSON (associationId/funcName/group/id/session/step/stillLogin/traceId/type/uid/userContext)
tag3 = "5008" # bizAppid
tag4 = 3 (INT8) # = type
tag5 = 180B safedeviceid # 设备指纹(base64)
tag6 = ""
tag7 = ""
tag8 = 210B userAction JSON # 风控行为轨迹
tag9 = ""
}
field1 = STRUCT { # 设备基础信息
tag0 = "ed0db8334cadd236c00cadf7e11ab5a5" # hdid (32 hex)
tag1 = "13.4.22" # App版本
tag2 = "1.0.80138" # SDK版本
tag3 = ""
tag4 = "127.0.0.1" # 占位
tag5 = "xiaomi" # 厂商
tag6 = ""
}
field2 = STRUCT { # 设备详情
tag0 = 1 (INT8)
tag1 = "M2102J2SC" # 型号 thyme
tag2 = "02df398797432eadefcc12767119ad5e80999389" # 设备唯一ID(40 hex)
tag3 = "android"
tag4 = "M2102J2SC,30,11" # 型号,SDK,版本
tag6 = "1080" # 屏宽 (tag5缺失)
tag7 = "2120" # 屏高
tag8 = "7c5387e0539c023c31c4ff0e807e7256117385ee" # 另一设备ID(40 hex)
}
field3 = STRUCT { # 登录凭证
tag3 = "hy_300023887" # name (虎牙号示例;手机号登录时直接放手机号)
tag4 = "772ed992b0e161276f44ec63671e60155c506294" # password = SHA1(明文)
tag5 = LIST["5008"] # appid列表
tag6 = 1 (INT8)
tag7 = {} (空map)
tag8 = [] (空simplelist)
}
}
```
### 2.4 原始可读字符串(完整)
TAF 序列化,可读字符串全量提取如下(关键字段用换行标出):
```
AAAD9xADLDxCADGd81YMaHV5YXVkYndlYnVpZg9oeXBhc3N3b3JkTG9naW59... ← WUP 头
└─ "huyaudbwebui" ← servant
└─ "hypasswordLogin" ← func
_wup_data 字段(关联元数据 JSON:
{"associationId":8193,
"funcName":"hypasswordLogin",
"group":1,
"id":4097, ← msgType
"session":3251699,
"step":1,
"stillLogin":false,
"traceId":"0b8f098ff64a5bdc-23473-94783833787595172451",
"type":3,
"uid":0,
"userContext":""}
业务数据:
5008 ← bizAppid (appId)
PQwemAN9NHkZKoMqVT... ← safedeviceid (设备指纹, base64)
userAction JSON:
{"curl":"登录页",
"furl":"我的",
"latitude":"-1.0",
"longitude":"-1.0",
"ssid":"",
"user_action":[
{"id":"24","time":"1787595171950","x":"277","y":"1057"},
{"id":"11","time":"1787595172444","x":"296","y":"952"}]}
设备信息字段:
ed0db8334cadd236c00cadf7e11ab5a5 ← hdid (硬件ID)
13.4.22 ← App 版本
1.0.801386 ← 某版本号
127.0.0.1 ← 回环地址(占位)
xiaomi ← 厂商
M2102J2SC ← 设备型号 (thyme)
M2102J2SC,30,11 ← 型号,SDK版本,版本
android ← 系统
1080 / 2120 ← 分辨率
7c5387e0539c023c31c4ff0e807e7256117385ee ← 另一个设备ID
登录凭证:
hy_300023887 ← name (虎牙号示例;手机号登录时直接放手机号)
772ed992b0e161276f44ec63671e60155c506294 ← password (SHA1)
结尾:
wupudbrequest_v0 ← WUP 请求类型标记
AAFAgAxnfOMmAyoDA== ← base64 尾巴(签名/校验)
```
---
## 三、WUP 请求的三层结构
```
┌──────────────────────────────────────────────────────┐
│ 第1层: WUP/TAF 外层 │
│ servant = "huyaudbwebui" │
│ func = "hypasswordLogin" │
│ _wup_data = { associationId, funcName, group, id, │
│ session, step, stillLogin, traceId, │
│ type, uid, userContext } │
├──────────────────────────────────────────────────────┤
│ 第2层: 业务数据 (AppLgnPasswordLoginReq) │
│ bizAppid = 5008 │
│ name = "hy_300023887" │
│ password = SHA1(明文) │
│ userAction = 风控行为 JSON │
│ safedeviceid / hdid / 设备信息 │
├──────────────────────────────────────────────────────┤
│ 第3层: 网络传输 │
│ TLS 1.3 → 116.162.209.x:443 (udblgn.huya.com) │
│ (自定义 BoringSSL / hyssl) │
└──────────────────────────────────────────────────────┘
```
---
## 四、网络层(实证)
- **密码登录走 TLS 443**(不是之前看到的 80 端口图片 CDN)
- 目标 IP`116.162.209.83-86``udblgn.huya.com`kunluncan CDN
- TLS 层:libhycrypto.so = 定制 BoringSSLhyssl),符号已 strip
- 连接池:App 启动时预建立,登录时复用
- **HTTP body = 原始 TAF 二进制(1015字节),NOT base64**base64 是 hook 层返回值的表示形式,发送前已解码)
---
## 四·五、纯 Python 重放验证(✅ 成功)
**关键结论:纯 Python 可以复刻密码登录请求,服务端返回完整登录响应。**
```
POST https://udblgn.huya.com/open/hy/passwordLogin
Content-Type: application/x-wup
Body: 原始 TAF 二进制 (1015字节, 非base64)
```
重放金标准请求(`wup_passwordlogin_taf.bin`)后,服务端返回 **1514 字节登录响应**
| 字段 | 值 |
|---|---|
| **uid** | `1199666914671` |
| **name** | `hy_300023887` |
| **手机号掩码** | `001******7524` |
| **token** | 346 字节 base64(已存 `evidence/huya_token.txt` |
| **uc_states** | `1`(成功标记) |
这证明:
1. ✅ 请求格式 100% 正确(服务端无 BAD_REQUEST
2. ✅ 设备指纹(safedeviceid/hdid)可复用(重放旧值仍通过)
3. ✅ userAction 可复用(旧轨迹未被风控拒绝)
4. ✅ TLS 指纹不阻断
> 注:此验证是「重放」,即复用已抓到的完整请求。要批量登录新账号,还需编码器动态构造新请求(替换 name/password/session/traceId/userAction)。
---
## 四·六、编码器 + 动态构造验证(✅ 完整成功)
**编码器已实现,逐字节复现金标准,且能动态构造全新请求。**
1. **`tools/huya_wup_encoder.py`** — 自检通过:用已知字段构造,输出与金标准逐字节一致(1015 字节)
2. **动态构造测试** — 用新 session3251799)、新 traceId 构造全新请求(1009 字节),发送后返回:
| 字段 | 值 |
|---|---|
| **uid** | `1199666914671` |
| **name** | `hy_300023887` |
| **手机号掩码** | `001******7524` |
| **token** | 全新 token`XAQBRJ3H...` |
这证明 **纯 Python 可以完整复刻虎牙密码登录**
1. ✅ 帧格式(JCE/WUP)逆向定稿
2. ✅ 编码器逐字节复现
3. ✅ session/traceId 可自由生成(服务端接受新值)
4. ✅ 设备指纹可复用
5. ✅ 动态构造请求返回有效登录响应(uid + token)
### userAction 随机化(✅ 已实测)
`userAction` 只是请求里的一个普通 JSON 字符串字段,编码器已暴露 `user_action_json` 参数。实测**随机坐标 + 随机时间戳**同样能通过登录(返回 uid + token),服务端对该字段不做严格校验。
编码器提供辅助函数:
- `make_user_action(now_ms=None)` — 生成随机 userAction JSON(坐标/时间戳/点击间隔随机)
- `make_trace_id(pid=0)` — 生成 traceId
> 未实测定论:批量高频登录时,服务端是否按**账号/设备/IP 维度**限流或风控。这需要实测才能确认,与 userAction 无关。
---
## 五、对「纯 Python 复刻」的启示(已实证更新)
**TLS 指纹已实测:不阻断。** 普通 Python `urllib` 直连 `udblgn.huya.com` 能正常收到业务响应。
要脱离 App 用 Python 发密码登录请求,需要:
1.**密码**`sha1(明文)` —— 已破解,纯 Python 可做
2.**name**`hy_虎牙号` —— 已知
3.**servant/func**`huyaudbwebui` / `hypasswordLogin` —— 已知
4.**WUP 帧格式**:标准 JCE RequestPacket,已 100% 定稿(见第二节)
5.**Content-Type**`application/x-wup`body = 原始 TAF 二进制
6.**重放验证**:服务端返回 uid + token(纯 Python 可行)
7.**TAF/JCE 编码器**`tools/huya_wup_encoder.py`(自检通过,逐字节复现)
8.**_wup_data 元数据**`session`/`traceId` 可自由生成(服务端接受新值)
9.**设备指纹(safedeviceid/hdid**:可复用旧值(缓存一次即可)
10.**userAction**:随机坐标/时间戳即可通过(编码器内置 `make_user_action()`
> 唯一待实测项:批量高频登录时的账号/设备/IP 维度限流(与 userAction 无关)。
---
## 六、关联证据文件
- `huya-wup-plain.jsonl` — 第一次明文抓包(sendMsg JSON 层,305 事件)
- `huya-wup-full3.jsonl` — 完整 WUP 序列化(含本次密码登录 1356 字节)
- `wup_passwordlogin_taf.bin` — 金标准:1015 字节 TAF 二进制(= HTTP body,编码器自检依赖)
- `wup_passwordlogin_base64.bin` — 金标准:1356 字节 base64hook 返回值)
- `wup_response_badreq.bin` — 服务端响应帧(383 字节,returnCode=104
- `tools/huya_wup_encoder.py` — WUP 帧编码器(自检通过,逐字节复现金标准,含 `make_user_action`/`make_trace_id`
- hook 脚本:`hook_huya_wup_full.js`
- runner`run_huya_netcapture.py`
> 含有效登录 token 的响应文件(`wup_response_login.bin`、`wup_response_new_session.bin`、`huya_token.txt`)已加入 `.gitignore`,不提交。
---
## 七、结论与下一步
已完成并验证:
1.**TLS 指纹**:实测不阻断(Python urllib 正常收到业务响应)
2.**TAF 编码器**`tools/huya_wup_encoder.py`,逐字节复现金标准
3.**纯 Python 登录**:重放 + 动态构造均返回 uid + token
4.**userAction 随机化**:随机坐标/时间戳通过
待实测(唯一未定论项):
1. **批量高频登录的限流/风控**:需用编码器连续发请求,观察账号/设备/IP 维度是否触发限制(错误码、频率阈值)
2. **集成进 `core/huya/login.py`**:把 APP 密码登录(`/open/hy/passwordLogin`)作为 Web 登录被风控阻断时的替代路径