feat(dfp): 🔑 RC4 key=APK内嵌appkey常量(datadiv@3912240), 全流程零设备依赖闭环 (R38-R39)

This commit is contained in:
yml2213
2026-08-29 11:01:51 +08:00
parent 4868a3b0e8
commit 5fa1f6d082
13 changed files with 43643 additions and 2 deletions
+31
View File
@@ -1599,3 +1599,34 @@ full: 7c da | 11 | 69 c9 f5 28 9c 4d 46 | 95 6f 21 | 10 bb 80
### 端到端伪造路径 (已无阻塞)
JSON 构造 → gzip_wrap → RC4(捕获 key) → wire body → POST. 密钥每轮经 hook_hy.js 一挂即得.
## §11.67 R38-R39: 🏆 密钥溯源定案 — RC4 key = APK 内嵌常量, 全流程零设备依赖 (2026-08-29)
### 追踪过程 (教训先行)
- spawn 存活问题: 必须用两阶段配方三脚本 (bypass_msaoaid_maps_art_callsite + mask_frida_maps_only + 11s 后 patch_guard_block_termination) — 单挂 skip_cleanup 会在登录态路径秒死 (用户指正!)
- 登录 md5 正确姿势: udbauthunify!0x32e71c = md5_sret(out&, in), x0 是输出槽 onEnter 必空 (R34 误读根源); 输入 = k1(32hex) + getkey(nonce) → AESkey 派生 (R14 已知链, 本次活体复证 in1 hex 直接可见 "865a4924..." 前缀!)
### 密钥来源定案 (三层排除 → 实锤)
1. 排除落盘: /data/data 全 grep hex 文本 + turing 文件原始字节 = 无
2. 排除设备派生: md5(hdid/guid/signature/...) 全否; 跨天跨重注册稳定 → 非会话随机
3. **实锤: evidence/dfp_datadiv_full.json 字符串表 @3912240 = "865a4924a40897ac1fcfe6b4c2abc798", 紧邻 "dfpReport"/"appid"/"terminal"/"huyaudbnimoui"** — libhydeviceid .data (datadiv 加密) 内嵌 turing appkey 常量!
### 865a49 家族全景 (三个兄弟, 各属一个子系统)
| 常量 | 尾 6 hex | 来源 | 用途 |
|---|---|---|---|
| RC4 key | abc798 | libhydeviceid .data 常量 (datadiv) | **dfpReport 报文加密** |
| k1 | cbb0e3 | BusinessCfg+0x10 (datadiv) | appSign=md5("5008_ver_k1") + AESkey=md5_char16(k1+getkey) |
| channelKey | cbb045 | resinfo (AES-ECB, HuyaUdb... 密钥) 服务端下发 | t1 设备指纹 |
### 全链终态 (每一步都有代码级证据)
```
APK 内嵌: appkey 865a..c798 (datadiv 加密 .data) ──运行时解密──┐
指纹 JSON 采集 (Athena/Hebe/terminal/version) │
→ gzip (1f8b08, level9) │
→ RC4(appkey) keystream XOR ────────────────────────────────┘
→ wire body (前10B=keystream⊕gzip头, 即"magic")
→ taf/wup 封装 → POST wsapi.huya.com /dfpReport
```
- 登录链 (已破): uid+getkey → xxtea/AES-OTP (§11.44); appSign=md5("5008_ver_k1") (R15)
- 会话链: Perseus SecureRandom 16字符 → RSA 信封 (R34) — 独立通道, 与 dfpReport 无关
- **端到端伪造 = 纯离线**: JSON 构造 + tools/dfp_rc4.py (key 为常量), 无需设备!
+379
View File
@@ -0,0 +1,379 @@
{
"script-loaded": [
{
"event": "script-loaded"
}
],
"java-md5-hooked": [
{
"event": "java-md5-hooked"
}
],
"java-digest": [
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "46c8591368de4c8f19f8668b45b80e31",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "4fcb130eb3b47f0d3916d1cd92a5b4be",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "93cfd7f6e97ff8df4e1a255cb9bf8dac",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "6d50d5b8412eba4daa4363bac3fd4cbc",
"in_parts": ""
},
{
"event": "java-digest",
"algo": "MD5",
"out": "0708f0ba839c2be70fd0a39d8bb6fb03",
"in_parts": ""
}
],
"hy-armed": [
{
"event": "hy-armed"
}
]
}
+379
View File
@@ -0,0 +1,379 @@
{
"script-loaded": [
{
"event": "script-loaded"
}
],
"hy-armed": [
{
"event": "hy-armed"
}
],
"java-md5-hooked": [
{
"event": "java-md5-hooked"
}
],
"java-digest": [
{
"event": "java-digest",
"algo": "MD5",
"out": "37fe6db03febc05f6966dfc84c19a8ab"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "46c8591368de4c8f19f8668b45b80e31"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "4fcb130eb3b47f0d3916d1cd92a5b4be"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "93cfd7f6e97ff8df4e1a255cb9bf8dac"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "5cb4c302204a8fbc8dad11a838a3d2ba"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c9a4f4089e6493d7e4cb4ba8df7e40fe"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "8bedcda6f084bfd2d1ebfe397aff0e8f"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "34887b39dfd812a2f9b4ffecdfca5a15"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "e91a91301fa53aa2d15c999739a58e44"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "a255b00458d1a5c548aaf768e9f5b959"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "1aeb7bdcd488671fe3561207696d77bf"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "2e5f190dcb08d31b7c833a5c2f9172e1"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "c2d705043d7ca0f8842702eeef30b6a4"
},
{
"event": "java-digest",
"algo": "MD5",
"out": "71ee9b2f9c6819caa86764ece8950905"
}
]
}
+7
View File
@@ -0,0 +1,7 @@
{
"script-loaded": [
{
"event": "script-loaded"
}
]
}
+7
View File
@@ -0,0 +1,7 @@
{
"script-loaded": [
{
"event": "script-loaded"
}
]
}
File diff suppressed because it is too large Load Diff
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""R36: hook libz deflate/inflate — 抓 XXTEA 输入明文 + 隐藏加密路径 backtrace."""
import json, subprocess, time
from pathlib import Path
import frida
REMOTE="127.0.0.1:31878"; ADB="5dd8c93f"; PACKAGE="com.duowan.kiwi"
RE=Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
HERE=Path(__file__).resolve().parent.parent
OUT=HERE/"evidence"/("keytrace_"+time.strftime("%H%M%S")+".json")
def clear_turing():
for d in ("app_turingdfp","app_turingfd"):
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"rm -rf /data/data/{PACKAGE}/{d}/*"],capture_output=True)
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"find /data/data/{PACKAGE} -name 'resinfo*' -delete"],capture_output=True)
def main():
clear_turing()
d=frida.get_device_manager().add_remote_device(REMOTE)
subprocess.run(["adb","-s",ADB,"shell","am","force-stop",PACKAGE],capture_output=True)
time.sleep(1.5)
pid=d.spawn([PACKAGE]); print(f"[*] spawn pid={pid}",flush=True)
s=d.attach(pid)
try:
b=s.create_script((RE/"evidence/scripts/bypass_msaoaid_maps_skip_cleanup.js").read_text()); b.load()
except Exception as e: print(f"[*] bypass err {e}",flush=True)
d.resume(pid)
result={}; got={"post":False,"out":False}
seen_fns=set()
def events_ok(p):
seen_fns.add(p.get('fn')); return True
def on(m,_):
if m.get("type")=="error":
txt=str(m)
if "ClassNotFoundException" in txt: return
print(f"[JS] {txt[:160]}",flush=True); return
p=m.get("payload") or {}
ev=p.get("event")
if ev=="post": got["post"]=True; print(f"[+] POST {p['num']}B",flush=True)
elif ev=="armed-hy": print("[*] hy chain armed",flush=True)
elif ev=="call":
if len(seen_fns)<99: pass
elif ev=="call" and events_ok(p): got["out"]=True
elif ev=="deflate-found": print(f"[*] deflate export in {p['mod']}",flush=True)
elif ev=="inflate-in": print(f"[+] inflate-in {p['len']}B via {p['mod']}",flush=True)
result.setdefault(ev or "misc",[]).append(p)
sc=s.create_script((HERE/"tools/frida/hook_keytrace.js").read_text())
sc.on("message",on); sc.load()
t0=time.time()
while time.time()-t0<150:
time.sleep(2)
if got["out"] and got["post"]: time.sleep(4); break
json.dump(result,open(OUT,"w"),indent=2)
print(f"[*] saved {OUT}",flush=True)
try: s.detach()
except Exception: pass
if __name__=="__main__": main()
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""R38b: RC4 key 诞生点追踪 (MD5 transform 消息积累)."""
import json, subprocess, time
from pathlib import Path
import frida
REMOTE="127.0.0.1:31878"; ADB="5dd8c93f"; PACKAGE="com.duowan.kiwi"
RE=Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
HERE=Path(__file__).resolve().parent.parent
OUT=HERE/"evidence"/("keytrace2_"+time.strftime("%H%M%S")+".json")
def clear_turing():
for d in ("app_turingdfp","app_turingfd"):
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"rm -rf /data/data/{PACKAGE}/{d}/*"],capture_output=True)
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"find /data/data/{PACKAGE} -name 'resinfo*' -delete"],capture_output=True)
def main():
clear_turing()
d=frida.get_device_manager().add_remote_device(REMOTE)
subprocess.run(["adb","-s",ADB,"shell","am","force-stop",PACKAGE],capture_output=True)
time.sleep(1.5)
pid=d.spawn([PACKAGE]); print(f"[*] spawn pid={pid}",flush=True)
s=d.attach(pid)
try:
b=s.create_script((RE/"evidence/scripts/bypass_msaoaid_maps_skip_cleanup.js").read_text()); b.load()
except Exception as e: print(f"[*] bypass err {e}",flush=True)
d.resume(pid)
result={}; state={"post":False,"key":False}
def on(m,_):
if m.get("type")=="error":
t=str(m)
if "ClassNotFoundException" not in t: print(f"[JS] {t[:150]}",flush=True)
return
p=m.get("payload") or {}
ev=p.get("event")
if ev=="post": state["post"]=True; print("[+] POST fired",flush=True)
elif ev=="key-site": state["key"]=True; print(f"[+] KEY ARRIVED: {p.get('key')} md5calls={p.get('md5calls')} states={p.get('nstates')}",flush=True)
elif ev=="hy-armed": print("[*] hy armed",flush=True)
elif ev=="java-md5-hooked": print("[*] java digest hooked",flush=True)
elif ev=="key-copies-done": print(f"[*] key copies: {p.get('n')}",flush=True)
result.setdefault(ev or "misc",[]).append(p)
sc=s.create_script((HERE/"tools/frida/hook_keytrace2.js").read_text())
sc.on("message",on); sc.load()
t0=time.time()
while time.time()-t0<220:
time.sleep(3)
if state["key"] and state["post"]: time.sleep(5); break
json.dump(result,open(OUT,"w"),indent=2)
print(f"[*] saved {OUT} post={state['post']} key={state['key']}",flush=True)
try: s.detach()
except Exception: pass
if __name__=="__main__": main()
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""R39: 登录流程 md5 输入捕获 — 两阶段配方 (与 hook_final_capture.py 同款):
spawn挂起 -> 双bypass装载 -> resume -> 稳定11s -> patch_guard -> 业务钩子
"""
import json, time
from pathlib import Path
import frida
REMOTE="127.0.0.1:31878"; PACKAGE="com.duowan.kiwi"
RE=Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
HERE=Path(__file__).resolve().parent.parent
OUT=HERE/"evidence"/("loginmd5_"+time.strftime("%H%M%S")+".json")
def main():
d=frida.get_device_manager().add_remote_device(REMOTE)
pid=d.spawn([PACKAGE])
print(f"[*] spawned {pid}",flush=True)
s=d.attach(pid)
# 双重防护: callsite bypass + maps 掩盖
s.create_script((RE/"evidence/scripts/bypass_msaoaid_maps_art_callsite.js").read_text()).load()
s.create_script((RE/"evidence/scripts/mask_frida_maps_only.js").read_text()).load()
d.resume(pid)
print("[*] resumed, 稳定 11s...",flush=True)
time.sleep(11)
s.create_script((RE/"evidence/scripts/patch_guard_block_termination.js").read_text()).load()
print("[*] patch_guard on",flush=True)
result={}; state={"udb":0}
def on(m,_):
if m.get("type")=="error":
t=str(m)
if "ClassNotFoundException" not in t: print(f"[JS] {t[:150]}",flush=True)
return
p=m.get("payload") or {}
ev=p.get("event")
if ev=="udb-md5":
state["udb"]+=1
print(f"[+] udb-md5 #{state['udb']} in1={str(p.get('in1'))[:100]} out={str(p.get('out'))[:80]}",flush=True)
elif ev=="udb-armed": print("[*] udb md5 armed",flush=True)
elif ev=="java-digest":
out=p.get('out','')
if out.startswith('865a') or out.startswith('') and False: pass
print(f"[J] digest {p.get('algo')} out={out[:16]} in={repr((p.get('in_parts') or ''))[:70]}",flush=True)
result.setdefault(ev or "misc",[]).append(p)
sc=s.create_script((HERE/"tools/frida/hook_login_md5.js").read_text())
sc.on("message",on); sc.load()
print("[*] 请在 App 中: 退出登录 -> 账号密码重新登录 (窗口 8 分钟)",flush=True)
t0=time.time()
while time.time()-t0<480:
time.sleep(5)
if state["udb"]>=12: time.sleep(6); break
json.dump(result,open(OUT,"w"),indent=2)
print(f"[*] saved {OUT} udb={state['udb']}",flush=True)
try: s.detach()
except Exception: pass
if __name__=="__main__": main()
+5 -2
View File
@@ -8,8 +8,11 @@
不是魔数! 密钥同则 magic 同)
-> 尾部 10B 为 gzip 流之后的附加段 (decompressobj unused_data)
密钥 = 32 字符 hex ASCII 串 (如 865a4924a40897ac1fcfe6b4c2abc798), 每注册轮换.
捕获点: libhydeviceid.so!0x60e6c onEnter x1 = 密钥串 (tools/frida/hook_hy.js).
密钥 = 32 字符 hex ASCII 串 = **APK 内嵌静态常量** (非随机、非设备派生!):
libhydeviceid.so .data (datadiv 加密) 字符串表 @offset 3912240, 紧邻 "dfpReport"/"appid"/"terminal":
[3912240] "865a4924a40897ac1fcfe6b4c2abc798" ← turing appkey/通道密钥 (R39 实锤)
同族兄弟: k1=...cbb0e3 (BusinessCfg+0x10), channelKey=...cbb045 (resinfo 服务端下发)
新版本 APK 离线重提取: unidbg hydev harness 跑 datadiv 解密, 或 0x60e6c x1 一次抓取.
XXTEA/静态密钥 f15e... 与 dfpReport 无关 (那是 hdid 子系统) — 45 函数零调用之谜即此.
"""
from __future__ import annotations
+143
View File
@@ -0,0 +1,143 @@
// R38: 追踪 RC4 key (32hex) 的诞生点 — Java MessageDigest + udb md5 + 0x60e6c 反查副本
'use strict';
function emit(o){ try{ send(o); }catch(e){} }
function hexb(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(b=>('0'+b.toString(16)).slice(-2)).join(''); }catch(e){ return ''; } }
var nEvents = 0;
// ---- 1) Java MessageDigest 全量 (md5/sha1) ----
setImmediate(function(){
Java.perform(function(){
try {
var MD = Java.use('java.security.MessageDigest');
MD.digest.overload().implementation = function(){
var algo = this.getAlgorithm();
var out = this.digest();
try {
var hex = Array.prototype.map.call(out, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
nEvents++;
emit({event:'java-digest', algo: algo, out: hex});
} catch(e){}
return out;
};
MD.digest.overload('[B').implementation = function(inp){
var algo = this.getAlgorithm();
var out = this.digest(inp);
try {
var hex = Array.prototype.map.call(out, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
var inHex = Array.prototype.map.call(inp, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
nEvents++;
emit({event:'java-digest', algo: algo, out: hex, in_hex: inHex.substring(0,2048)});
} catch(e){}
return out;
};
emit({event:'java-md5-hooked'});
} catch(e){ emit({event:'java-e', e:String(e).substring(0,150)}); }
});
});
// ---- 2) udbauthunify md5 (0x32e71c) 原始参数 ----
function armUdb(){
var u = Process.findModuleByName('libudbauthunify.so');
if (!u) return false;
try {
Interceptor.attach(u.base.add(0x32e71c), {
onEnter(args){
this.a = [];
for (var i=0;i<4;i++) this.a.push({x:String(args[i]), h:hexb(args[i],96)});
this.lr = this.returnAddress;
},
onLeave(){
try {
var outs = [];
for (var i=0;i<2;i++) outs.push(hexb(this.a[i].x ? ptr(this.a[i].x) : ptr(0), 96));
nEvents++;
emit({event:'udb-md5', args:this.a, out_re:outs, lr: String(this.lr)});
} catch(e){}
}
});
emit({event:'udb-armed'});
return true;
} catch(e){ return false; }
}
// ---- 3) 0x60e6c 到位点 + 全内存反查 key 副本 ----
function armHy(){
var h = Process.findModuleByName('libhydeviceid.so');
if (!h) return false;
try {
Interceptor.attach(h.base.add(0x60e6c), {
onEnter(args){
try {
var s = '';
try { s = args[1].readCString(64); } catch(e){}
nEvents++;
emit({event:'key-site', x1:String(args[1]), key:s});
if (s && s.length === 32) {
setTimeout(function(){
var pat = '';
for (var i=0;i<16;i++) pat += s.substr(i,2).split('').join('')+' ' ;
pat = s.substring(0,16).split('').map(function(c){ return ('0'+c.charCodeAt(0).toString(16)).slice(-2); }).join(' ');
var n=0;
for (var r of Process.enumerateRanges('rw-')) {
if (r.size > 96*1024*1024) continue;
var ms=[];
try { ms = Memory.scanSync(r.base, r.size, pat); } catch(e){ continue; }
for (var m of ms){
if (n>=10) break;
n++;
emit({event:'key-copy', addr:String(m.address), src: r.file? r.file.path : String(r.base), around: hexb(m.address.sub(160), 352)});
}
if (n>=10) break;
}
emit({event:'key-copies-done', n:n});
}, 50);
}
} catch(e){ emit({event:'key-e', e:String(e).substring(0,150)}); }
}
});
// 4) JNI 边界 0x20e924 参数
Interceptor.attach(h.base.add(0x20e924), {
onEnter(args){
if (nEvents > 3000) return;
var rows=[];
for (var i=0;i<3;i++) rows.push({x:String(args[i]), h:hexb(args[i],48)});
nEvents++;
emit({event:'jni-boundary', args:rows});
}
});
emit({event:'hy-armed'});
return true;
} catch(e){ emit({event:'hy-e', e:String(e).substring(0,150)}); return false; }
}
var udb=false, hy=false;
var poll = setInterval(function(){
if (!udb) udb = armUdb();
if (!hy) hy = armHy();
if (udb && hy) clearInterval(poll);
}, 200);
// ---- 5) SSL_write 同轮密文 ----
var done = false;
for (var mod of Process.enumerateModules()){
var addr = null;
try { addr = mod.getExportByName('SSL_write'); } catch(e){}
if (!addr) continue;
Interceptor.attach(addr, {
onEnter(args){
if (done) return;
try {
var num = args[2].toInt32();
if (num < 60 || num > 60000) return;
var u = new Uint8Array(args[1].readByteArray(num));
var s = '';
for (var i=0;i<u.length;i++) s += (u[i]>=32 && u[i]<127) ? String.fromCharCode(u[i]) : '.';
if (s.indexOf('dfpReport') < 0) return;
done = true;
var hex = Array.prototype.map.call(u, function(x){return ('0'+x.toString(16)).slice(-2)}).join('');
emit({event:'post', num:num, hex:hex});
} catch(e){}
}
});
}
emit({event:'script-loaded'});
+137
View File
@@ -0,0 +1,137 @@
// R38b: RC4 key 诞生点终极追踪 — MD5 transform 消息积累 + 到位点反查 + Java digest 输入
'use strict';
function emit(o){ try{ send(o); }catch(e){} }
function hexb(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(b=>('0'+b.toString(16)).slice(-2)).join(''); }catch(e){ return ''; } }
var nEvents = 0;
var CAP = 2500;
// ---- 1) MD5 transform 消息积累 (libhydeviceid!0xc37c0, ror#7 核心) ----
var md5msgs = {}; // state -> [blockHex,...]
var md5order = [];
var md5calls = 0;
function armHy(){
var h = Process.findModuleByName('libhydeviceid.so');
if (!h) return false;
try {
Interceptor.attach(h.base.add(0xc37c0), {
onEnter(args){
if (md5calls > 1200) return;
md5calls++;
var st = args[0].toString();
var blk = hexb(args[1], 64);
if (!md5msgs[st]) { md5msgs[st] = []; md5order.push(st); if (md5order.length>60) {} }
md5msgs[st].push(blk);
}
});
// ---- 2) 0x60e6c 到位点 ----
Interceptor.attach(h.base.add(0x60e6c), {
onEnter(args){
try {
var s = '';
try { s = args[1].readCString(64); } catch(e){}
if (s.length !== 32) return;
nEvents++;
emit({event:'key-site', key:s, md5calls: md5calls, nstates: md5order.length});
// 倒出全部 MD5 消息 (每 state 拼接 blocks, 截 512B)
var dumped = 0;
for (var st of md5order){
if (dumped >= 40) break;
var full = md5msgs[st].join('');
nEvents++;
emit({event:'md5-msg', state: st, nblk: md5msgs[st].length, hex: full.substring(0, 1024)});
dumped++;
}
// 内存反查 key 副本
setTimeout(function(){
var pat = s.substring(0,16).split('').map(function(c){ return ('0'+c.charCodeAt(0).toString(16)).slice(-2); }).join(' ');
var n=0;
for (var r of Process.enumerateRanges('rw-')){
if (r.size > 96*1024*1024) continue;
var ms=[];
try { ms = Memory.scanSync(r.base, r.size, pat); } catch(e){ continue; }
for (var m of ms){
if (n>=10) break;
n++; nEvents++;
emit({event:'key-copy', addr:String(m.address), src: r.file? r.file.path : String(r.base), around: hexb(m.address.sub(192), 448)});
}
if (n>=10) break;
}
emit({event:'key-copies-done', n:n});
}, 30);
} catch(e){ emit({event:'key-e', e:String(e).substring(0,150)}); }
}
});
emit({event:'hy-armed'});
return true;
} catch(e){ return false; }
}
// ---- 3) Java MessageDigest: update 输入积累 ----
setImmediate(function(){
Java.perform(function(){
try {
var MD = Java.use('java.security.MessageDigest');
var pend = {}; // hashcode -> [hexchunks]
MD.update.overload('[B').implementation = function(b){
try {
var k = this.hashCode();
if (!pend[k]) pend[k]=[];
if (pend[k].length < 8) {
pend[k].push(Array.prototype.map.call(b, function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('').substring(0,2048));
}
} catch(e){}
return this.update(b);
};
MD.digest.overload().implementation = function(){
var algo = this.getAlgorithm();
var out = this.digest();
try {
var k = this.hashCode();
var hex = Array.prototype.map.call(out, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
if (nEvents < CAP) { nEvents++; emit({event:'java-digest', algo:algo, out:hex, in_parts:(pend[k]||[]).join('')}); }
delete pend[k];
} catch(e){}
return out;
};
MD.digest.overload('[B').implementation = function(b){
var algo = this.getAlgorithm();
var out = this.digest(b);
try {
var hex = Array.prototype.map.call(out, function(b2){ return ('0'+(b2&0xff).toString(16)).slice(-2); }).join('');
var inHex = Array.prototype.map.call(b, function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('');
if (nEvents < CAP) { nEvents++; emit({event:'java-digest', algo:algo, out:hex, in_parts:inHex.substring(0,4096)}); }
} catch(e){}
return out;
};
emit({event:'java-md5-hooked'});
} catch(e){ emit({event:'java-e', e:String(e).substring(0,150)}); }
});
});
// ---- 4) SSL_write 同轮标记 ----
var done = false;
for (var mod of Process.enumerateModules()){
var addr = null;
try { addr = mod.getExportByName('SSL_write'); } catch(e){}
if (!addr) continue;
Interceptor.attach(addr, {
onEnter(args){
if (done) return;
try {
var num = args[2].toInt32();
if (num < 60 || num > 60000) return;
var u = new Uint8Array(args[1].readByteArray(num));
var s = '';
for (var i=0;i<u.length;i++) s += (u[i]>=32 && u[i]<127) ? String.fromCharCode(u[i]) : '.';
if (s.indexOf('dfpReport') < 0) return;
done = true;
nEvents++;
emit({event:'post', num:num});
} catch(e){}
}
});
}
var armed=false;
var poll = setInterval(function(){ if (armHy()){ armed=true; clearInterval(poll);} }, 200);
emit({event:'script-loaded'});
+82
View File
@@ -0,0 +1,82 @@
// R39: 登录时 udbauthunify md5 正确捕获 — sret 约定: x0=out槽, x1=in
'use strict';
function emit(o){ try{ send(o); }catch(e){} }
function hexb(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(b=>('0'+b.toString(16)).slice(-2)).join(''); }catch(e){ return ''; } }
function rdStr(p){
// libc++ std::string: b0&1==0 -> SSO (len=b0>>1, data=+1); else heap (len@+8, data@*+16)
try {
var b0 = p.readU8();
if ((b0 & 1) === 0){
var l = b0 >> 1;
if (l > 22) return {t:'susp', len:l, v: hexb(p.add(1), 48)};
return {t:'s', len:l, v: p.add(1).readUtf8String(l)};
}
var hl = p.add(8).readU64().toNumber();
if (hl > 8192) return {t:'err', v:'too long '+hl};
return {t:'b64h', len:hl, v: hexb(p.add(16).readPointer(), Math.min(hl, 512))};
} catch(e){ return {t:'err', v:String(e)}; }
}
var n = 0;
function armUdb(){
var u = Process.findModuleByName('libudbauthunify.so');
if (!u) return false;
try {
Interceptor.attach(u.base.add(0x32e71c), {
onEnter(args){
this.outp = args[0];
this.in1 = rdStr(args[1]);
this.in2 = rdStr(args[2]);
this.raw = [hexb(args[1], 64), hexb(args[2], 64)];
this.lr = String(this.returnAddress);
},
onLeave(){
if (n > 300) return;
n++;
emit({event:'udb-md5', in1:this.in1, in2:this.in2, raw:this.raw,
out: rdStr(this.outp), lr:this.lr});
}
});
emit({event:'udb-armed'});
return true;
} catch(e){ emit({event:'udb-e', e:String(e).substring(0,150)}); return false; }
}
var armed = false;
var poll = setInterval(function(){ if (armUdb()){ armed=true; clearInterval(poll); } }, 200);
// Java digest 带输入 (登录 Java 侧可能也算)
setImmediate(function(){
Java.perform(function(){
try {
var MD = Java.use('java.security.MessageDigest');
var pend = {};
MD.update.overload('[B').implementation = function(b){
try {
var k=this.hashCode();
if(!pend[k]) pend[k]=[];
if (pend[k].length<8) pend[k].push(Array.prototype.map.call(b,function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('').substring(0,2048));
} catch(e){}
return this.update(b);
};
MD.digest.overload().implementation = function(){
var out=this.digest();
try {
var k=this.hashCode();
var oh=Array.prototype.map.call(out,function(b){return ('0'+(b&0xff).toString(16)).slice(-2);}).join('');
emit({event:'java-digest', algo:this.getAlgorithm(), out:oh, in_parts:(pend[k]||[]).join('')});
delete pend[k];
} catch(e){}
return out;
};
MD.digest.overload('[B').implementation = function(b){
var out=this.digest(b);
try {
var oh=Array.prototype.map.call(out,function(b2){return ('0'+(b2&0xff).toString(16)).slice(-2);}).join('');
var ih=Array.prototype.map.call(b,function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('');
emit({event:'java-digest', algo:this.getAlgorithm(), out:oh, in_parts:ih.substring(0,4096)});
} catch(e){}
return out;
};
emit({event:'java-md5-hooked'});
} catch(e){}
});
});
emit({event:'script-loaded'});