# 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
