虎牙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:
@@ -0,0 +1,194 @@
|
||||
# 虎牙 App 登录 — APK 静态逆向分析(libudbauthunify.so)
|
||||
|
||||
> 目标:`apks/huya-13.4.22-115315-live.apk`(158MB,versionCode=115315)
|
||||
> 分析对象:`lib/arm64-v8a/libudbauthunify.so`(4.7MB,UDB 认证统一库)
|
||||
> 方法:`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 | BoringSSL(AES/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) # XXTEA,key = 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 |
|
||||
Reference in New Issue
Block a user