65 lines
3.3 KiB
Markdown
65 lines
3.3 KiB
Markdown
# TNG eWallet 滑动验证码(阿里云 Captcha)逆向笔记(2026-08-03)
|
||
|
||
## 现象
|
||
|
||
注册/登录手机号页点「继续」→ 弹阿里云滑动拼图验证 → 滑块拖对通过 →
|
||
**不返回**(TTCaptcha 未回调 TNG 业务层)→ 手动点「继续」→ 再次弹验证 → 循环。
|
||
|
||
## 回调链(1.9.10 dex 逆向)
|
||
|
||
```
|
||
用户滑动成功
|
||
→ JS postMessage → CaptchaWebViewDialog$2.a (action=sendAliyunCaptchaVerifyData, data 含 success/message)
|
||
→ Captcha.generateResult(char, zzbfs) → JSON {code, retCode, message, certifyId}
|
||
→ setVerifyResult(true) → Captcha$1(Handler) → VerificationCallback.onSuccess(result)
|
||
→ TTCaptcha 反射 Proxy → TTCaptchaCallback.callBack(result)
|
||
→ parseJson → TTCaptchaResponse{code, certifyId}
|
||
code==0 且 certifyId 非空 ?
|
||
→ notifySuccess(certifyId) → TTInListener.success → TNG 业务层提交 RPC
|
||
→ notifyFailure(code) / handleFailure("Result is null"|"Invalid code or certifyId")
|
||
→ 服务端二次校验 certifyId 失败
|
||
→ quake 抛 CaptchaNeededException("Captcha needed")
|
||
/ CaptchaNotPassedException("Captcha not passed")
|
||
→ 验证拦截器再弹滑块 → 循环
|
||
```
|
||
|
||
## 关键类(dex 定位)
|
||
|
||
| 类 | 作用 |
|
||
|----|------|
|
||
| `com.aliyun.captcha.Captcha`(classes10) | 单例,verify/generateResult/showDialog |
|
||
| `com.aliyun.captcha.CaptchaWebViewDialog` + `$2` | 滑块 WebView + JS postMessage 桥 |
|
||
| `com.aliyun.TigerTally.captcha.api.TTCaptcha` | TigerTally 封装,**反射**调 aliyun Captcha |
|
||
| `com.aliyun.TigerTally.captcha.core.TTCaptchaCallback` | 解析 result,code==0 且 certifyId 非空才 success |
|
||
| `my.com.tngdigital.captcha.TigerTallyApiWrapper` | TNG 业务侧封装(Kotlin 协程 showCaptcha) |
|
||
| `...aliservice.quake.CaptchaNeededException` / `CaptchaNotPassedException` | 服务端要验证 / 验证未通过 |
|
||
| `...amcs.CaptchaConfigCenter` / `CaptchaInitializer` | 远程下发 wafCaptchaKey / captcha_switch |
|
||
| `...opmpaasexpress.interceptor.OpMpVerifyInterceptor` 等 | RPC 验证拦截器,触发滑块 |
|
||
|
||
## 判定点(本次 hook 已打点)
|
||
|
||
1. `Captcha.generateResult` 返回的 JSON —— **certifyId 是否为空**(滑块是否真正拿到服务端签发)
|
||
2. `CaptchaWebViewDialog$2.a` —— JS postMessage 的 data 内容
|
||
3. `TTCaptchaCallback.callBack/notifySuccess/notifyFailure` —— TNG 是否拿到 certifyId
|
||
4. `CaptchaNeeded/NotPassedException` 构造 message —— 服务端二次校验失败原因
|
||
5. `TTCaptcha.verifyByReflect/buildParams` —— captcha 参数(region/appKey 等)
|
||
|
||
## 根因候选
|
||
|
||
- **TigerTally 设备指纹(umidToken)异常**:`hookTigerTally` 短路了
|
||
`TigerTallyAPI.init/initCommon` 与 `t.B.genericNt1`(防 ANR fork 卡死)。
|
||
若 captcha 服务端用 umidToken 校验设备,缺失/变化会导致 certifyId 校验失败。
|
||
- **captcha 全量方法打点拖慢 JS 桥回调**(已修复:改为精准打点)。
|
||
- **region 错误**:`TTCaptcha.buildParams` 用 `t.B.genericNt14()` 取 region。
|
||
|
||
## 抓 logcat 判定
|
||
|
||
```powershell
|
||
powershell -File scripts/logcat-tng.ps1
|
||
```
|
||
|
||
复现滑块 → 观察:
|
||
- `captcha JS postMessage` 后是否有 `captcha RET generateResult`(含 certifyId)
|
||
- `captchaCb CALL notifySuccess` 是否出现(成功)还是 `notifyFailure`
|
||
- `captcha EXC ...CaptchaNotPassedException` 的 msg
|