# MariBank 风控与注册载荷说明

> 客户端检测分层、register 请求字段含义、菲律宾突破原因、USB 调试与 Hook 关系。  
> 关联：[`MariBank_2026-07-06_菲律宾突破.md`](MariBank_2026-07-06_菲律宾突破.md) · [`MariBank实现说明.md`](MariBank实现说明.md) · [`手机操作手册.md`](手机操作手册.md)

---

## 1. 风控两层模型

| 层级 | 谁在做 | 失败表现 | bypass 方式 |
|------|--------|----------|-------------|
| **客户端本地** | SafeMode、SHPSSDK、SG ADB 页 | 弹窗、全屏拦截、自杀 | Xposed boolean / Settings / finish Activity |
| **服务端** | `api.seabank.ph` / `api.maribank.com.sg` | 4067012 / 3100012 | 让出站 attestation「够干净」+ 区域策略 |

**DFP `code=0` 只表示上报收到，不等于注册会通过。**

干净机对照（25078RA3EY）：**开 USB 调试 → SG 本地 ADB 页；关调试 → SG OTP 可过**。说明本地检测与服务端决策 **相互独立**。

---

## 2. 注册请求载荷结构（App 发出）

加密前 JSON（`MariBankEncrypt` / `uvwuvwuv.uvwvuww` 入口）典型结构：

```json
{
  "cyCode": "63",
  "phone": "<RSA 加密>",
  "scene": "REGISTRATION",
  "step": "BE",
  "rdVerifyInfo": {
    "bioStatus": 0,
    "data": "<SHPSSDK native attestation 密文>",
    "dataKey": "<attestation 密钥>",
    "deviceFingerprint": "段1|段2|段3|00|0",
    "fvInfo": {},
    "afExtInfo": {
      "modeInCall": "N",
      "modeInCommunication": "N",
      "modeCallScreening": "N"
    },
    "publicKeyAuthen": "pk2",
    "random": "...",
    "softTokenActivated": false
  }
}
```

流程：**App 本地采集 → 拼 JSON → native 加密 → POST `/uapi/v2/register`**

---

## 3. 字段说明

### 3.1 `deviceFingerprint`

pipe 分隔字符串，示例：

```text
jrKyNF/Fx4gcnzVpf1u9bw==|WJMksio9SaKKuyk1KMSilUGivdF+...|TXeh8FyEf/8qHdAS|00|0
  ↑ Base64 段1          ↑ Base64 段2（设备哈希）     ↑ 短码  ↑ 风险码|标志
```

| 部分 | 含义 | Hook 能否改 |
|------|------|-------------|
| 前两段 Base64 | 设备 / 环境哈希，服务端可索引黑名单 | 换 serial/android_id 后 **重新生成** |
| 第三段 | 短码 | 随 SDK 变 |
| 最后 `\|xx\|y` | 风险摘要（如 Root+Hook `\|09\|1`） | ✅ 已净化为 `\|00\|0` |

**只改尾部不够**：服务端还验 `data`/`dataKey` 解密内容。

### 3.2 `data` / `dataKey`

- 由 **`libshpssdk_bank.so` native** 生成并签名  
- 内含 Root / Hook / 调试等 attestation，**Java 层改 JSON 字段无法重写密文**  
- SG 3100012 时，多半此层或设备黑名单未过；PH 7/6 成功时服务端 **接受了** 当前密文

### 3.3 `afExtInfo`（银行 App 上报，非 PC 添加）

```json
"afExtInfo": {
  "modeInCall": "N",
  "modeInCommunication": "N",
  "modeCallScreening": "N"
}
```

| 字段 | 推测含义 | `"N"` |
|------|----------|-------|
| `modeInCall` | 是否正在通话 | No |
| `modeInCommunication` | 是否通信/音频占用 | No |
| `modeCallScreening` | 来电筛选等相关状态 | No |

- **来源**：App / SDK 读系统状态写入 `rdVerifyInfo`  
- **去向**：随 register 加密后发给服务端  
- **当前模块**：**未专门修改** 这三项（原样上报）  
- **用途**：反欺诈辅助信号，**不是** USB 调试开关

### 3.4 其他常见字段

| 字段 | 说明 |
|------|------|
| `cyCode` | 国家码：PH=`63`，SG=`65` |
| `step` | `BE` 首次注册 → 成功后可到 `BSO`（OTP） |
| `action` | `OTP_SMS_TRIGGER` 触发短信验证码 |
| `bioStatus` | 生物识别状态，注册时多为 `0` |

---

## 4. 为何 USB 调试开着仍能发 OTP（菲律宾实测）

### 4.1 两个「USB 调试」不是一回事

| | PC 侧 adb | App 内部读到的值 |
|--|-----------|------------------|
| 你开 USB 调试 | ✅ 能 `adb shell` | 被 Hook **伪装为关闭** |

### 4.2 模块已做的 ADB bypass（`MariBankRootBypassHook`）

**Java Settings：**

- `adb_enabled` / `adb_wifi_enabled` / `development_settings_enabled` → `0`

**系统属性（`MariBankShpsNativeHook`）：**

- `init.svc.adbd` → `stopped`
- `persist.sys.adb_enable` → `0`

**UI：**

- 全屏「ADB / Wireless ADB Detected」页 → `Activity.finish()`
- 相关 Toast 拦截

因此：**PC 连着 adb，App 仍可能认为未开调试**，本地不拦、register 载荷也不带「adb 开」的自报字段。

### 4.3 与干净机对照

| 环境 | USB 调试 | 结果 |
|------|----------|------|
| 干净机（无 Hook） | 开 | 本地 ADB 页，进不了 OTP |
| 干净机 | 关 | ✅ OTP |
| Pixel 6 + LSPosed + Shamiko | **开** | ✅ PH OTP（Hook 伪装） |

### 4.4 注意

- native 仍可能用 Hook 未覆盖的路径读调试状态  
- **SG 更严**，开 adb 风险高于 PH  
- 文档仍建议测 SG 时 **关 USB 调试**

---

## 5. 菲律宾能发验证码的真实原因

### 5.1 能确定

- `api.seabank.ph` 返回 **`code=0`**，step 进入 **BSO**，**OTP_SMS_TRIGGER** 成功  
- 同一台机、同一套 Hook 下 **SG 仍 3100012** → 差异在 **服务端**，非「没风控」

### 5.2 7/3 失败 → 7/6 成功的变化

| 能力 | 7/3 | 7/6 |
|------|-----|-----|
| riskToken 尾部净化 | ✅ | ✅ |
| 加密前 register 明文 Hook | ❌ | ✅ |
| Attestation / 环境 Hook | 弱 | ✅ |
| Shamiko 藏 Magisk | 无/未配 | ✅ |
| 换 serial / android_id | 无 | ✅ |

**不是单一开关**，而是 **Shamiko + 新设备 ID + 加密前/采集链净化** 组合后，PH 服务端认为 attestation **可接受**。

### 5.3 高概率推断

1. **PH / SG 两套 API、两套规则** — 同一载荷 PH 过、SG 不过  
2. **PH 侧设备黑名单** — Pixel 6 在 SG 测多次，PH 可能未标记  
3. **7/3 的 4067012** — bypass 不完整，非「PH 永远不能 Root 注册」

### 5.4 无法无源码 100% 证实

- PH 后台具体哪条规则放行  
- `data` 解密后哪一位从拒变收  

---

## 6. Magisk / LSPosed / Shamiko 分工

```
Magisk（Root 权限）
  └── Zygisk
        ├── LSPosed → 加载 xposed-module（改 Java 检测、抓加密前 JSON）
        └── Shamiko → 对银行进程隐藏 Magisk/LSPosed
Magisk 模块 maribank_device_spoof → resetprop 换 serial 等
```

| 组件 | 作用 |
|------|------|
| **Magisk** | Root |
| **LSPosed** | 运行 Xposed 模块（与经典 Xposed 同 API，见 [`Hook指南.md` §0](Hook指南.md)） |
| **Shamiko** | 进程内 Hide Root，改善 native attestation |
| **Xposed 模块** | SafeMode / ADB / 加密前净化 |

---

## 7. 服务端可能校验项（反推）

| 校验项 | 说明 |
|--------|------|
| `rdVerifyInfo.data` / `dataKey` | native attestation 解密 |
| `deviceFingerprint` 段 1/2 | 设备黑名单 |
| DFP 历史画像 | 与 register 是否一致 |
| 区域策略 | PH 松 / SG 严（实测） |
| IP / 号码 / 频率 | 次要，非本次主因 |

---

*最后更新：2026-07-06*
