- 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辅助函数 - 新增证据金标准 + 协议文档
5.7 KiB
5.7 KiB
虎牙 App 密码登录协议 — Frida 抓包实证
状态:密码登录完整链路已抓包实证 方法:spawn + libmsaoaidsec 绕过 + hook sendMsg/jbyteArray2str/str2jbyteArray(TLS 加密前的明文层) 证据文件:
/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/evidence/derived/huya-wup-plain.jsonlJava 反编译:/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 加密前明文,抓包实证):
{
"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 返回)
{
"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 | setDeviceInfo(hdid + safedeviceid) |
0x1001 (4097) |
1 | 密码登录(MsgLogin) |
0xb000001 |
1 | 登录后 getLoginData |
0xb000024 |
1 | 登录后获取数据 |
0xb000013 |
1 | getConfig(TAF 二进制,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)
七、待确认项(剩余,影响较小)
- userAction 是否必填/可复用:风控行为采集(点击轨迹),批量登录时能否固定/复用同一份,还是每次都要真实模拟。
- 登录接口是否校验 OTP dckey:密码登录请求本身是否需要先拿到 dckey(本次抓包 OTP 在密码登录之后触发,说明密码登录可能不依赖 dckey)。
- token 的 TAF 结构解析:响应 token 的 Base64 内是 TAF 二进制(
9QDzAAED...),需解析出 uid/appid/时间戳等字段。