Files
live-hub-py/docs/虎牙App登录-APK静态分析.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

195 lines
7.8 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 登录 — APK 静态逆向分析(libudbauthunify.so
> 目标:`apks/huya-13.4.22-115315-live.apk`158MBversionCode=115315
> 分析对象:`lib/arm64-v8a/libudbauthunify.so`4.7MBUDB 认证统一库)
> 方法:`nm -D` 导出符号 + `objdump` 反汇编 + `strings` 字符串提取(纯静态,无需 hook)
> 结论:**App 登录 = WUP 长连接 + XXTEA/AES 双层加密**,全部加密函数与 servant 已定位。
---
## 一、关键结论(一句话)
虎牙 App 登录的**设备风控加密**由 `libudbauthunify.so` 实现,算法链是:
```
明文 → cred_pack 打包 → XXTEA 加密 → cred_pack 拼装 → MD5 派生 key → AES-128-ECB 加密 → 密文
```
`dckey` = **Login Credential(登录凭据)**,通过 `MsgGetCred` / `MsgRequestLgnCred` 获取,加密后经 `udbdf.huya.com/dckey/check` 上传。
---
## 二、关键 native 库定位
| so 库 | 大小 | 作用 |
|---|---|---|
| **`libudbauthunify.so`** | 4.7MB | **UDB 认证统一库(核心)**,含全部登录/加密逻辑 |
| `libhycrypto.so` | 1.9MB | BoringSSLAES/RSA 标准实现) |
| `libhydeviceid.so` | 4.1MB | 设备 ID 生成 |
| `libtscsdk.so` | 1.5MB | 数美(TrustKernel)设备指纹 SDK(对应 zztfly 请求) |
| `libtea.so` | 409KB | XXTEA 算法 |
| `libmtpencrypt.so` | 809KB | MTP 加密 |
---
## 三、加密体系(已 100% 破解,来自反汇编)
### 3.1 加密函数清单
| 函数 | 地址 | 说明 |
|---|---|---|
| `hyudb_crypt_util::xxtea_encrypt` | 0x32e83c | **XXTEA 加密**(第一层) |
| `hyudb_crypt_util::xxtea_decrypt` | 0x32ece8 | XXTEA 解密 |
| `hyudb_crypt_util::md5_char16` | 0x32e71c | **MD5 派生 16 字节 key** |
| `hyudb_crypt_util::md5_char32` | 0x32e7ac | MD5 派生 32 字节 |
| `UdbAESUtil::encrypt` | 0x250038 | **AES-128-ECB 加密**(第二层) |
| `UdbAESUtil::decrypt` | 0x2501a4 | AES 解密 |
| `AESkeyMgr::getkey` | 0x26871c | **AES key 缓存管理**map<int,map<int,string>> |
| `hyudb_packet_util::cred_pack` | 0x45xxxx | **cred(dckey) 二进制打包** |
| `hyudb_packet_util::cred_unpack` | — | cred 解包 |
| `encode_xxtea` / `decode_xxtea` | 0x330058/0x3306cc | XXTEA 编解码封装 |
### 3.2 加密模式确认(反汇编证据)
**AES 是 ECB 模式 + ZeroPadding**,证据来自 `UdbAESUtil::encrypt`0x250038)反汇编:
```asm
; 计算长度 & 0xf,非 16 倍数则 push_back(0) 补齐(ZeroPadding
and w11, w11, #0xf
...
bl push_back(0) ; 补零
; 每 16 字节独立调用 _encrypt(单块),无 IV 参与 → ECB 模式
loop:
bl UdbAESUtil::_encrypt(ptr16, out) ; 逐块 AES
add x24, x24, #0x10 ; +16
```
### 3.3 完整加密调用链(`hyudb_otp_encrypt` 0x32fa24 还原)
```
hyudb_otp_encrypt(x0=key, w1=2, w2=len, x3..x5=字段, w6=4, x7=buf, out)
├─ cred_pack(sp+0xb0, x7) # 打包第一个字段
├─ xxtea_encrypt(sp+0xc8, sp+0xe0, x24) # XXTEAkey = x0 参数
├─ cred_pack(sp+0x98, <header字段>) # 打包 header
├─ cred_pack(sp+0x98, sp+0xc8) # 打包 XXTEA 密文
├─ cred_pack(sp+0x98, x23) # 打包第5参数字段
├─ AESkeyMgr::getkey(i, i) # 取 AES key 字符串
├─ string::insert(...) # key 拼接
├─ md5_char16(key_str) # MD5 派生 16 字节 key
├─ UdbAESUtil::C1(md5key) # 用 MD5 结果构造 AES
└─ UdbAESUtil::encrypt(packed, md5key) # AES-128-ECB 加密
```
调用方:`BusinessCfg::getOtp(uid, otp, ...)`0x268bbc~0x268ca0)→ `hyudb_otp_encrypt(...)`
---
## 四、硬编码 key 候选(rodata 段)
| 字符串 | 长度 | 备注 |
|---|---|---|
| **`HuyaUdb1928374650qwertyuiop`** | 27B | **最强候选**"HuyaUdb" + 数字 + 字母键盘序) |
| `275d0ff676c0d65114acdefbd2ad87a3` | 16B | 32 hex,正好 AES-128 key 长度 |
| `0123456789ABCDEF` / `0123456789abcdef` | 16B | 常见默认 key |
> XXTEA key 与 AES key 源需 hook 最终确认(hook `xxtea_encrypt` 第3参、`md5_char16` 输入)。
---
## 五、dckey = Login Credential
符号证据链:
```
MsgGetCred / MsgRequestLgnCred / MsgResponseLgnCred
HandlerGetCred / HandlerRequestLoginCred / HandlerResponseLoginCred
AutoCredLogin(自动凭据登录)
BusinessCfg::getCred / getCredEx / setSafeDeviceId
AUTO_CRED_LOGIN_TIMER
```
即:**dckey 就是「登录凭据(credential)」**,App 启动后用设备指纹换取,登录时作为风控凭证提交。
---
## 六、完整登录 servant 清单(TAF/WUP 结构名)
从 so 的 rodata 提取全部 `wup.*` 结构名:
### 登录类(核心)
| servant/结构 | 用途 |
|---|---|
| **`AppLgnPasswordLoginReq/Resp`** | **App 密码登录** |
| **`AppLgnOtpLoginReq/Resp`** | **App 一键(OTP)登录** |
| **`AppLgnCredentialLoginReq/Resp`** | **dckey 凭据登录** |
| **`AppLgnSmscodeLoginReq/Resp`** | 短信验证码登录 |
| `AppLgnMobileSendSmsReq/Resp` | 手机号发短信 |
| `AppLgnSessionSendSmsReq/Resp` | 会话发短信 |
| `AppLgnSecondAuthLoginReq/Resp` | 二次认证 |
| `AppLgnAntiViolentLoginReq/Resp` | 反暴力登录 |
| `AppLgnRefreshPicReq/Resp` | 刷新验证码图 |
| `AppLgnThirdLoginReq/Resp` | 第三方登录 |
### 密码/注册类
```
AppPasswordLoginReq/Resp # 密码登录(另一组)
AppCredentialLoginReq # 凭据登录
AppAnonymousLoginReq/Resp # 匿名登录
AppMobileRegisterReq # 手机注册
AppRegSendSms / AppRegCheckMobile / AppRegCheckUser
AppRegSmscodeRegister / AppRegSmscodeModifyPassword / AppRegSmscodeResetPassword
AppRegTokenRegister / AppRegTokenModifyPassword / AppRegTokenResetPassword
AppRegUidVerifySmscode
AppBindLoginMobile / AppBindNewMobile(绑定手机)
AppBypassRouteReq/Resp # 旁路路由
```
### servant 名(TAF 服务名)
```
huyaudb # UDB 主服务
huyaudbwebui # 抓包里 wsapi.huya.com 的 servant
huyaudbnimoui # NIM UI 服务
passport # 护照服务
```
---
## 七、其他关键 token/字段
```
violentToken / sessionToken # 反暴力 token / 会话 token
enpack_header / depack_header # header 打包/解包(含 NEWKEY
key_version[%d] / key_id[%d] # key 版本/ID 管理
lgnExtParam / lgnProtect # 登录扩展参数 / 登录保护
loginAppId / loginAppName / loginDeviceName / loginStrategy / loginType
```
`enpack_header` + `NEWKEY` 解释了抓包里 dckey body 的 **100 字节固定头**:那是打包的 header(key 版本、key_id、固定字段),加密只作用于变长数据体。
---
## 八、给 hook 的精确落点(静态分析直接给出)
| 目标函数 | hook 什么 | 得到什么 |
|---|---|---|
| `hyudb_crypt_util::xxtea_encrypt` | 第3参(XXTEA key) + 第2参(明文) + 返回(密文) | **XXTEA key + 明文结构** |
| `hyudb_crypt_util::md5_char16` | 输入 string + 输出 16B | **AES key 源**MD5 前明文) |
| `AESkeyMgr::getkey` | 返回值 string | **AES key 字符串** |
| `UdbAESUtil::encrypt` | 入参(明文) + 返回(密文) | 验证 AES 模式/填充 |
| `hyudb_packet_util::cred_pack` | 各字段 | **dckey 二进制结构** |
| `BusinessCfg::getOtp` | 入参 | OTP 生成逻辑 |
| `MsgRequestLgnCred` 序列化前 | WUP 结构 | **登录凭据请求明文** |
| OkHttp `CertificatePinner.check` | — | SSL unpin,解 cdn.wup 长连接 |
---
## 九、抓包 ↔ so 对应关系(验证闭环)
| 抓包现象 | so 证据 |
|---|---|
| dckey body 前 100B 固定 | `enpack_header`/`cred_pack` 打包的固定 header |
| dckey body 后段变长 | XXTEA+AES 加密的数据体 |
| dfpReport t2 魔数 `571882cf664bb39401ee` | cred_pack 的固定标识 |
| selectOperator.t5 / dfpReport.t2 同前缀 13B | 同一固定 header(非 RSA,是打包结构头) |
| 登录走 cdn.wup.huya.com 抓不到 | App 登录 servant 走 WUP 长连接 + SSL Pinning |