dfpReport: 确定加密为逐字节XOR(动态keystream)+同步pair捕获+IDA导出线索, 记录破解进度

This commit is contained in:
yml2213
2026-08-26 14:17:58 +08:00
parent acb0a737eb
commit 4eec01568f
38 changed files with 4942 additions and 3 deletions
+44
View File
@@ -0,0 +1,44 @@
# Hook 脚本运行与捕获约定(强制遵守)
> 适用范围:本仓库所有 `scripts/hook_*.py` / `probe_*.py` / `scan_*.py` 的创建、修改与运行。
> 原则:**脚本挂上 hooks 后,用后台任务运行;数据实时写日志;目标数据一命中,立刻主动停止任务。绝不用 bash 前台 `sleep` 等超时结束再看结果。**
## 1. 运行方式(必须)
- 启动:一律 `bash` 工具的 `run_in_background: true`,例如:
```
cd /Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0 && \
.venv/bin/python -u scripts/hook_xxx.py > /tmp/hook_xxx.log 2>&1 &
```
脚本内部必须 `print(..., flush=True)`(或 `-u`),保证日志实时落盘。
- 观察:用 `bash` 前台 `tail -f /tmp/hook_xxx.log`(或 `grep` 关键字)实时查看日志,**不要** `sleep 120` 后一次性读。
- 停止:一旦日志中出现目标数据(`[hit]` / `[wire]` / `[FOUND]` 等命中标记),立即:
```
pkill -f hook_xxx.py # 或 job_kill 对应后台任务
```
保存 `evidence/*.json` 后即可分析。不需要等脚本自身的超时窗口走完。
- 配套交互:需要用户在手机上操作(退出登录→重新登录)时,脚本打印提示后立即进入等待,hook 数据实时刷日志;用户操作完成后我们随时 `tail` 查看,命中即杀。
## 2. 脚本自身结构(必须)
- 主循环用 `time.sleep(5)` 轮询,但**每条捕获都立即 `send()`**`on_message` 里 `print(flush=True)`。
- 超时窗口(如 150s)只是兜底,不是等待方式:数据命中即可提前退出(`pkill`/`job_kill`)。
- 捕获结果写 `evidence/` 下 JSON`script.on('message')` 全程收集事件,退出前统一落盘;但如果提前被杀,落盘逻辑可能不执行 —— 因此**命中即打印+写入**:`on_message` 里命中类型直接 `OUT` 文件追加写入,保证被杀前数据已持久化。
- 统一模块:`RE = Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")`frida 环境 + bypass 脚本在此)。
- 设备连接:`frida.get_device_manager().add_remote_device("127.0.0.1:31877")`(设备上 frida-server 14.2.18 监听 0.0.0.0:31877macOS 侧 `adb forward tcp:31877 tcp:31877`)。
- spawn 流程(稳定版,参考 `hook_genbiz.py`):
1. `device.spawn(["com.duowan.kiwi"])`
2. 加载 `bypass_msaoaid_maps_art_callsite.js`
3. 加载 `mask_frida_maps_only.js`
4. `device.resume(pid)``sleep 11`
5. 加载 `patch_guard_block_termination.js`
6. 再 `create_script` 主 hook JS
- 注意:**不要直接 attach 运行中的 kiwi 进程**App 有 msaoaid 反调试,attach 会被杀/闪退);必须 spawn + 三件套 bypass。
- 注意:脚本里的 JS 若在 `resume` 前 `load()`,目标 so 尚未加载,hook 会落空 —— 模块相关枚举/attach 用 `setInterval` 轮询或放在 resume+11s 之后。
## 3. 常见坑
- `frida-ps -U` 正常但 remote spawn 报 `TransportError`:检查 `adb forward --list`,必须 `tcp:31877 -> tcp:31877`。
- 设备上会同时存在多个 kiwi 进程(主进程 + cloudpatch/logcat 子进程);**hook 必须挂在我们 spawn 的主进程 pid 上**,用户手动操作的若为旧实例,hook 会空转(日志 0 命中)。操作前先 `am force-stop com.duowan.kiwi` 清掉旧实例。
- datadiv 导出名是 `.datadiv_decode...`(带点前缀),匹配用 `name.indexOf('datadiv') >= 0`,不要用 `=== 0`。
- `libhydeviceid.so` 业务符号全部混淆/内部化(只导出 `hy_*` syscall 包装 + JNI_OnLoad),dfpReport 加密体生成函数不在导出表;静态搜不到魔数 `571882cf664bb39401ee` 属正常(运行时拼装)。
+129
View File
@@ -0,0 +1,129 @@
# dfpReport 破解进度总结 (待破解#2)
> **当前状态**:加密算法已确定为**逐字节 XOR keystream**(非 XXTEA),明文 JSON 已全部拿到。
> 剩余关键问题:**keystream 每会话动态生成**,需找到其生成函数/种子。
> IDA 已导出两个 so 的完整反编译+反汇编:`/Users/yml/Downloads/so/{libhydeviceid,libudbauthunify}.so_export_for_ai`
---
## 一、已确定的结论(铁证)
### 1. dfpReport 加密 = 逐字节 XOR keystream(不是 XXTEA!)
**证据链**:
- 同会话 5 次 dfpReport(wire 间隔 3-6s),密文两两 XOR 非零位置 3947/3984 → keystream 每会话动态
- 但**密文前 10B 魔数恒定** `57 18 82 cf 66 4b b3 94 01 ee`(跨天、跨会话)→ 魔数是**明文头 XOR 固定值**或者**固定前缀**
- 8.23 各样本位置 11-22 部分相同 → 是明文固定字段,不是 keystream 泄漏
- 若为 XXTEA(hyudbxxt),则密文任何字节变化会扩散到全部 → 但实测前 10B 不动 → 排除 XXTEA
### 2. tag2 密文结构(3984B)
```
tag2 = [魔数 10B][XOR密文 3974B?]
```
- 明文 ≈ JSON(554B) + 采集二进制(3420B) ≈ 3974B,与"密文长度-魔数"吻合
- 但注意:3954B 对齐实验(偏移 0..9 all ~1% 相同率)未找到明文精确起点 → **加密输入可能不是纯 JSON,JSON 只是其中一部分**(pa 结构待最终确认)
### 3. 明文 JSON 完整捕获(554B,可铸造)
```json
{"appId":"5008","appVer":"13.4.22","appkey":"865a4924a40897ac1fcfe6b4c2cbb0e3",
"channel":"xiaomi","deviceId":"02df398797432eadefcc12767119ad5e80999389",
"deviceName":"M2102J2SC","hdid":"7c5387e0539c023c31c4ff0e807e7256117385ee",
"heightPixels":"2120","isCloud":0,"isForbidLog":1,"isHome":0,"isPre":0,"openAppId":"",
"savePath":"/data/user/0/com.duowan.kiwi/files/huyaudb","sdkVer":"1.0.80138",
"servantName":"huyaudbwebui","shareAppDataPath":"/data/user/0/com.duowan.kiwi/files/huyaudb",
"systemInfo":"android","systemVer":"M2102J2SC,30,11","terminalType":1,"testEnv":0,"widthPixels":"1080"}
```
- **hdid 字段 = 服务端返回的 device_id (t5)** `7c5387...` → 服务端回显本地明文,本地可完全控制设备身份!
- appkey `865a...cbb0e3` ≠ 静态 t1 `865a...cbb045` → appkey 来自运行时配置
### 4. 响应回显验证(t1/t5 本地可铸造)
- 重放任意 wire body → HTTP 200,344B 响应,同一 t1+t5,全新 t2
- t1(`865a4924a40897ac1fcfe6b4c2cbb045`) 静态埋于 libhydeviceid .data(0x3bb190, 0x3bb230, 0x3e0e50),datadiv 加载时解密
- **patch 明文实验**:改明文 JSON 的 hdid/appkey/deviceId(等长替换)后 app 崩溃 → 说明有校验或时序问题,但方向正确(见下"待办")
### 5. keystream 前 24B(从 5 组同步 pair 恢复)
```
# 修正对齐 off=0 (密文[10:] XOR 明文[0:]):
t=1379: 07 f8 60 f9 b8 bc 30 bf 76 4e d4 8d a8 f6 54 21 31 fa 47 53 72 63 ef 29
t=7268: 17 f9 70 e5 b8 3c 6c be 77 e6 ac cb c3 2a 6a 8c ef aa cd ce eb e5 67 a7
t=3695: 17 f9 70 f9 b1 3c 4c be 77 74 14 ee 5e 7c e0 88 3a e2 c3 2c 72 63 8c 10
...
```
各会话 keystream 不同 → **动态生成**,极可能种子 = 时间戳或会话随机 + 固定密钥
---
## 二、IDA 导出可用资源(用户新提供,重点!)
```
/Users/yml/Downloads/so/libhydeviceid.so_export_for_ai/
decompile/ # 3895 个 C 反编译
disassembly/ # 逐函数汇编
exports.txt # 1832 个导出 (含 70 个 .datadiv_decode)
function_index.txt, strings.txt, memory/...
/Users/yml/Downloads/so/libudbauthunify.so_export_for_ai/
decompile/252700.c # hyudbxxt::xxtea_encrypt 标准 XXTEA (dfp 无关,登录用)
```
**优先排查的加密函数**:
- `decompile/1107CC.c` 引用 `0x5718` 魔数常量 ×3!(sub_1107CC,调用者 0xa6a3c)← **最可疑是真加密/解密函数**
- `decompile/1D52C8.c``1D5844.c``294FB0.c``7BF8C.c` 也含 0x5718
- 大 XOR 循环候选:17F75C, 212B04, 21F98C, 2332D4, 23755C, 23C534, 26D7B0, 274BBC, B5A18
---
## 三、动态 hook 关键资产
### 抓同步 (明文, 密文) 对 —— 已成功!
`scripts/capture_pair_sync.py`:spawn+bp3 绕过 → SSL_write 命中 dfpReport 时 80ms 后全内存扫描 `{"appId":"5008"` → 同时刻明文。5 组同步 pair 在 `evidence/dfp_pair_sync.json`
### 环境
- RE repo venv: `/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0/.venv/bin/python -u`
- 远程 frida: `adb forward tcp:31877 tcp:31877` + `frida.get_device_manager().add_remote_device("127.0.0.1:31877")`
- 绕过:spawn 后先 `bypass_msaoaid_maps_art_callsite.js` + `mask_frida_maps_only.js` → resume → 11s 后 `patch_guard_block_termination.js`
- **hook 规则**:后台任务 + tail 实时看 + 命中即 pkill(见 `docs/Hook脚本运行与捕获约定.md`)
---
## 四、下一步行动(按优先级)
1. **读 IDA 反编译确认加密**:重点 `decompile/1107CC.c`(引用 0x5718!)及其调用者链 0xa6a3c → 找 keystream 生成函数(输入时间戳/随机种子 + 固定 key,输出 3974B 流)
2. **hook 加密函数**:定位后 hook,抓 (明文输入, key/种子, 密文输出) 三元组 → 直接复现纯 Python 加密
3. **验证 keystream 种子假设**:比对 5 组 keystream 的 Δ 与 wire 时间戳 Δ(3-6s 间隔,keystream 差异是否对应计数/时间)→ 若种子=时间戳,纯代码可复现
4. **patch 明文实验修复**:上次改明文崩溃可能因 datadiv 重解码或时序;改用 hook 加密函数输入 buffer 后直接改明文再放行,避免物理内存写
5. **最终目标**:纯 Python 生成 dfpReport 请求体 = 构造明文 JSON(改 hdid/deviceId/appkey 铸造新设备) + 魔数 + 复现 keystream 加密 → 重放得到全新 t1/t5
---
## 五、账号/数据资产
- 账号 `hy_300026595` / `aa778899`(老 ref `hy_300024708`)
- HAR:`/Users/yml/Desktop/抓包/hy/8.23/登录-{1,2,3,5}.har`(6 个 dfpReport wire,t2 len 3408-4237)
- 同一设备(小米 M2102J2SC, Android 11, 快照 `5dd8c93f`)所有 wire 魔数头相同
- 关键回显:hdid `7c5387e0539c023c31c4ff0e807e7256117385ee` = 明文 hdid = 响应 t5
## 六、关键文件索引
| 文件 | 内容 |
|---|---|
| `evidence/dfp_pair_sync.json` | **5 组同步 (密文+明文) pair**(最新最有价值) |
| `evidence/dfp_pair.json` | 早期 3 组 pair(wire len 4278/4397/4413) |
| `evidence/dfp_wire_stack.json` | 8 事件 5 dfpReport wire HEX |
| `evidence/dfp_plain_big.json` | 187 个堆命中(明文 JSON @0x7814096d19 等) |
| `evidence/dfp_datadiv_full.json` | .data 7895 个已解码字符串(t1 所在) |
| `scripts/capture_pair_sync.py` | 同步 pair 抓取脚本(可复用) |
| `/Users/yml/Downloads/so/libhydeviceid.so_export_for_ai/` | **IDA 反编译(新!)** |
## 七、新会话起点(最重要的下一步)
**IDA 反编译确认加密**:`/Users/yml/Downloads/so/libhydeviceid.so_export_for_ai/decompile/1107CC.c`
- 引用 `0x5718` 魔数 ×3,调用者 `0xa6a3c` → 极可能是 dfpReport 加解密核心
- 同时看:1D52C8.c, 1D5844.c, 294FB0.c, 7BF8C.c(均含 0x5718)
- 反汇编对应文件在 `disassembly/`.asm
**验证 keystream 种子**:evidence/dfp_pair_sync.json 有 5 组同步 pair,
两组 keystream 差 vs 时间戳差 → 判断种子是否时间戳/计数器。