分析方法:
让claude code opus 4.6写frida dump脚本dump出libbochk_aos.so,之后结合开源脱壳工具用jadx反编译
还使用了MCP工具:ida-pro-mcp 和jadx-ai-mcp
仅供安全研究学习使用,不得他用。
BOCHK App Root & Hooking Detection 完整分析报告
安全警告 URL 参数解码
1 | https://www.bochk.com/dam/securitywarning.html |
| 参数 | 值 | 含义 |
|---|---|---|
reason |
22 | Root检测错误码(BOCLFRootUtils.getRootErrorCode() 生成的10位二进制转十进制) |
hookingframeworks |
F4 | Promon Shield native 层检测到的 hooking framework 位掩码 |
return |
4 | 返回行为码:打开浏览器显示安全警告 |
reason=50 |
(另一个URL) | 恶意软件检测(MainActivity.a(C0566h) 触发) |
检测架构
graph TD
A["App启动"] --> B["jtqupujl.aP.attachBaseContext()
(extends Application)"]
B --> C["jtqupujl.Y.c() → d() → b()
System.loadLibrary('bochk_aos')"]
C --> D["libbochk_aos.so JNI_OnLoad
Promon Shield 初始化"]
D --> E["Native 检测引擎
SVC 直接系统调用"]
E --> E1["DoCodetracerDetection
sub_26B680"]
E --> E2["CodetracerDetection
sub_26BD20"]
E --> E3["AllowedPackagesForRootingCheck
protobuf 配置"]
E1 --> F["jtqupujl.U Service
native a()/b()/c()/d()"]
E2 --> F
F --> G["jtqupujl.G AbstractBinder
IPC 传递检测结果"]
G --> H["构建 URL
reason=22 & hookingframeworks=F4"]
H --> I["k.j().D(fragment, url)
Intent.ACTION_VIEW 打开浏览器"]
A --> J["BOCHKLaunchFlow.Launch()"]
J --> K["BOCHKLaunchFlow.K()
Java 层 Root 检测"]
K --> L["BOCLFRootUtils.checkRoot()
10项 RootBeer 检测"]
L -->|"rooted"| M["BOCLFRootUtils.getRootErrorCode()
生成 reason 码"]
M --> N["BOCHKLaunchFlow.Q()
上报 rootErrorCode 到服务器"]
L -->|"not rooted"| O["BOCHKLaunchFlow.F()
继续启动流程"]
第一层:Java Root 检测
入口:BOCHKLaunchFlow.K()
1 | // BOCHKLaunchFlow.K() — Root 检查决策 |
BOCLFRootUtils.checkRoot() — 10项检测
1 | return rootBeer.detectRootManagementApps() // bit9: Root管理App (Magisk/SuperSU) |
BOCLFRootUtils.getRootErrorCode() — reason 码生成
生成 10位二进制字符串,转十进制作为 reason 值:
| Bit (高→低) | 检测项 | 你的设备 |
|---|---|---|
| bit9 (MSB) | detectRootManagementApps() |
? |
| bit8 | detectPotentiallyDangerousApps() |
? |
| bit7 | detectTestKeys() |
? |
| bit6 | (固定0) | 0 |
| bit5 | checkForSuBinary() |
? |
| bit4 | checkSuExists() |
? |
| bit3 | checkForRWPaths() |
? |
| bit2 | (固定0) | 0 |
| bit1 | checkForRootNative() |
? |
| bit0 (LSB) | detectRootCloakingApps() |
? |
[!IMPORTANT]
reason=22= 十进制22 = 二进制0000010110
- bit4 (=1):
checkSuExists()检测到 su- bit2 (=1):
checkForRWPaths()检测到 RW 路径- bit1 (=1):
checkForRootNative()native层 root 检测
第二层:Promon Shield Native 检测 (hookingframeworks=F4)
初始化链
| 步骤 | 类 | 方法 | 作用 |
|---|---|---|---|
| 1 | jtqupujl.aP |
attachBaseContext() |
Application 入口,调用 Promon init |
| 2 | jtqupujl.Y |
c() → d() → b() |
加载 libbochk_aos.so |
| 3 | jtqupujl.Y |
a(Application) (native) |
初始化 Promon Shield |
| 4 | jtqupujl.U |
a(), b(), c(), d() (native) |
Service 中暴露检测结果 |
| 5 | jtqupujl.G |
a(), b(), c(), d() |
Binder IPC 代理检测结果 |
检测类型枚举 (jtqupujl.EnumC0539aa) — 17种完整映射
[!IMPORTANT]
以下映射通过 JADX 源码分析(每个枚举值对应一个aO子类)+ IDA protobuf 字符串 + Promon Shield 官方文档交叉验证得出。
| # | 枚举值 | 实现类 | Key字段 | 数据结构 | 推断检测类型 |
|---|---|---|---|---|---|
| 1 | m |
C0571m |
1-4 | bool + 3×int | Root检测 — 核心检测,keys 1-4 最小编号,3个int存root方法计数 |
| 2 | f |
C0562d |
257 (0x101) | bool | Frida 检测 — 单布尔值,检测frida-server/agent |
| 3 | b |
aQ |
513 (0x201) | bool | 调试器检测 (Debugger) — 单布尔值,反JDWP/ptrace |
| 4 | r |
C0559au |
769 (0x301) | bool | 重打包检测 (Repackaging) — 签名校验 |
| 5 | i |
ay |
1025-1030 | bool + 5×str | Hooking框架检测 — 包含框架名/路径/版本等5字段 |
| 6 | h |
C0573o |
1537 (0x601) | bool | 屏幕叠加/录屏检测 — 防止Overlay攻击 |
| 7 | q |
aG |
1793-1798 | bool + 5×str | 代码追踪器检测 (Code Tracer) — 与IDA中DoCodetracerDetection/CodetracerDetection对应 |
| 8 | n |
C0564f |
5633-5634 | bool + int | 模拟器检测 (Emulator) — int存模拟器类型码 |
| 9 | o |
aB |
6145-6146 | 2×bool | 无障碍服务检测 — 两个bool分别检测是否开启和是否恶意 |
| 10 | g |
K |
8705-8707 | str + 2×bool | 篡改检测 (Tampering) — 字符串存证书hash |
| 11 | l |
S |
8450-8451 | 2×bool | 虚拟环境检测 — 双布尔,d()=a或b任一触发 |
| 12 | k |
T |
12289-12291 | ComponentName + 2×str | 恶意Activity检测 — 存Activity组件名和包名 |
| 13 | c |
C0540ab |
16384 (0x4000) | bool | SSL Pinning/证书验证 — 高key值检测 |
| 14 | p |
C0549ak |
16640 | list(8-field) | 已安装App扫描 — 8字段详细记录每个可疑App信息 |
| 15 | d |
C0572n |
16897 (0x4201) | bool | 设备完整性检测 — Play Integrity / SafetyNet |
| 16 | j |
W |
17153 (0x4301) | bool | 密钥存储检测 — Keystore安全检测 |
| 17 | a |
aD |
LIVE_RESULT_SUCCESS | list(5-field) | 恶意App哈希匹配 — 与服务器下发hash比对 |
检测结果回调流程
graph LR
A["Native Detection
libbochk_aos.so"] -->|JNI| B["jtqupujl.Q.b()
注册观察者 (native)"]
B --> C["创建 aO 子类实例
(如 C0571m/C0562d等)"]
C --> D["InterfaceC0567i.a(aO)
回调观察者"]
D --> E["x1.b.a(aO)
BOCHK 回调处理"]
E -->|"enum a"| F["恶意App哈希匹配
→ load_unofficial_app_key"]
E -->|"enum p"| G["已安装App扫描
→ load_unofficial_app_key"]
D --> H["Promon内部处理
构建 securitywarning URL"]
H --> I["k.j().D()
打开浏览器"]
关键发现:x1.b 回调实现
x1.b 实现了 InterfaceC0567i,专门处理两种枚举的检测结果:
EnumC0539aa.a(aD类): 遍历恶意App列表,提取包名/hash/路径 → 上传为 JSONEnumC0539aa.p(C0549ak类): 遍历已安装App列表(8字段详细信息)→ 上传为 JSON- 两者合并后通过
h2.a.c("load_unofficial_app_key")上报到服务器
Native 层检测技术 (IDA 分析)
| 函数 | IDA地址 | 技术 |
|---|---|---|
DoCodetracerDetection |
sub_26B680 |
通过 SVC 直接系统调用扫描 /proc/self/maps,检测 Frida agent 内存映射 |
CodetracerDetection |
sub_26BD20 |
检测代码追踪器(Frida/Xposed/Substrate 线程名和内存特征) |
OnCodeTracerDetectedCallback |
内部回调 | 检测到后触发 pipe 通知 |
SyscallNo |
0x3c099 |
内联 SVC 系统调用号标记,绕过 libc hook |
hookingframeworks=F4 解析
F4 十六进制 = 244 十进制 = 二进制 11110100,表示 Promon Shield 通过 EnumC0539aa 的多个检测类型均返回阳性:
| Bit | 可能含义 |
|---|---|
| bit2=1 | Frida 检测(内存中发现 frida-agent) |
| bit4=1 | Xposed Framework |
| bit5=1 | Substrate/LSposed |
| bit6=1 | 代码追踪器/调试器 |
| bit7=1 | 其他检测 |
第三层:恶意软件检测 (reason=50)
在 MainActivity.a(C0566h) 中,如果检测到恶意软件:
1 | k.j().D(fragment, "https://www.bochk.com/dam/securitywarning.html?reason=50&srcApp=bochk"); |
恶意软件扫描流程: jtqupujl.aR → jtqupujl.aM.a() 扫描已安装App → 与服务器下发的 SHA-256 哈希比对 → 匹配则触发 reason=50。
第四层:CloudWalk 活体检测环境安全检查
CloudWalk SDK (cn.cloudwalk) 是 BOCHK 使用的人脸活体检测组件。在启动活体检测前,会进行独立的环境安全检查。
入口:CwBaseLiveFragment.checkRoot()
1 | // 1. 先检查 Root |
HookToolDetector 6项检测(加载 LibCwUtils.so)
| 方法 | 检测技术 | 详情 |
|---|---|---|
e() |
Xposed 类加载检测 | 尝试 ClassLoader.loadClass("de.robv.android.xposed.XposedHelpers") 和 "XposedBridge",加载成功=被 hook |
d() |
Xposed 异常栈检测 | 故意抛出异常,遍历 StackTrace 检查是否包含 Xposed 类名 |
f() |
内存映射检测 | 读取 /proc/self/maps,搜索 3 个 Xposed 相关 so 库名(混淆字符) |
a() |
Frida 线程检测 | 读取 /proc/[pid]/task/*/status,搜索 “frida”、“gmain”、“gdbus” 线程名 |
b() |
调试器 TracerPid 检测 | 读取 /proc/[pid]/status 的 TracerPid 字段,非0=被调试 |
isFileExists() |
Native 文件完整性 | 通过 LibCwUtils.so native 方法检测 sandbox/虚拟环境(创建测试文件 cw-test.txt,native 层验证文件是否真实存在) |
[!NOTE]
CloudWalk 还额外检测:
- 模拟器:
d.j().a(context)— 模拟器环境检测- HTTP 代理:
DeviceUtil.isHttpProxy()— 检测中间人代理- Mock 位置:
Location.isFromMockProvider()— GPS 位置模拟检测
关键类映射表
| 类 | 功能 |
|---|---|
com.bochklaunchflow.BOCHKLaunchFlow |
启动流程总控:Root检测→版本检查→黑名单→维护 |
com.bochklaunchflow.utils.BOCLFRootUtils |
Java Root检测:10项RootBeer检测 + 生成 reason 码 |
com.tradelink.boc.rootdetection.ui.RootDetectionActivity |
Root检测 Activity UI |
com.scottyab.rootbeer.RootBeer |
第三方 Root 检测库 |
cn.cloudwalk.libproject.hook.HookToolDetector |
CloudWalk Hook/Root/Frida 检测(加载 LibCwUtils.so) |
cn.cloudwalk.libproject.live.CwBaseLiveFragment |
活体检测入口,调用 checkRoot() |
jtqupujl.aP |
Promon Application 入口 |
jtqupujl.Y |
加载 libbochk_aos.so,初始化 Promon |
jtqupujl.U |
Service,暴露 native 检测结果 |
jtqupujl.G |
Binder IPC 代理 |
jtqupujl.aO |
检测结果 HashMap 存储 |
jtqupujl.EnumC0539aa |
17种检测类型枚举 |
jtqupujl.aR |
恶意软件扫描管理 |
jtqupujl.aM |
恶意软件应用匹配 |
jtqupujl.aS |
libjni_proxy_launcher.so 加载 |
com.bochk.base.utils.k.D() |
Intent.ACTION_VIEW 打开安全警告 URL |
总结
BOCHK App 使用 四层防护:
- Java RootBeer (
BOCLFRootUtils): 10项软检测,生成reason码(你的reason=22= su存在 + RW路径 + native root) - Promon Shield Native (
libbochk_aos.so): 通过内联 SVC 系统调用检测 Frida/Xposed/调试器,生成hookingframeworks码(你的F4= 多种框架被检测到) - 恶意软件扫描 (
jtqupujl.aR/aM): 比对服务器哈希数据库,触发reason=50 - CloudWalk 环境检查 (
HookToolDetector): 在人脸活体检测前执行 6 项独立检测(Xposed类加载/栈/maps + Frida线程 + TracerPid + native文件),加载LibCwUtils.so,还检测模拟器/HTTP代理/Mock位置
所有检测结果通过 k.j().D(fragment, url) → Intent.ACTION_VIEW 打开浏览器显示安全警告页面。
BOCHK 17种 Promon Shield 检测方法深度分析
[!IMPORTANT]
Promon Shield 对所有敏感字符串(frida/xposed/su/magisk等)进行了运行时加密,静态分析无法直接找到明文。以下分析结合了 IDA 反编译、JADX 源码及 Promon Shield 官方文档。
检测方法总览
graph TD
subgraph "Native Layer - libbochk_aos.so"
JIT["JIT代码生成器
动态组装 ARM SVC 指令"]
SVC["SVC #0 直接系统调用
绕过 libc hook"]
PROC["/proc 文件系统扫描
maps/status/mountinfo"]
GOT["GOT 表完整性验证"]
HASH["文件/段 Hash 校验"]
end
subgraph "Java Layer - jtqupujl.*"
OBS["InterfaceC0567i 观察者"]
ENUM["EnumC0539aa 17种类型"]
AO["aO 子类实例化"]
end
JIT --> SVC
SVC --> PROC
PROC --> AO
GOT --> AO
HASH --> AO
AO --> OBS
1. Root检测 (EnumC0539aa.m → C0571m)
Native 层 (sub_A87F8)
1 | 技术: 读取 /proc/self/mountinfo 检测可疑挂载 |
Java 层 (RootBeer)
1 | // BOCLFRootUtils.checkRoot() — 10项检测 |
reason=22 解码: 22 = 二进制 10110 → bit4(checkSuExists) + bit2(checkForRWPaths) + bit1(checkForRootNative)
IDA 关键地址: sub_A87F8 (mountinfo解析), protobuf AllowedPackagesForRootingCheck @ 0x36808
2. Frida检测 (EnumC0539aa.f → C0562d)
Native 层 — JIT SVC 代码追踪器
1 | 函数: DoCodetracerDetection (sub_26B680) |
IDA 关键地址: sub_26B680 (DoCodetracerDetection), sub_26BD20 (CodetracerDetection), 0x3c099 (SyscallNo), 0x2f91a (OnCodeTracerDetectedCallback)
3. 调试器检测 (EnumC0539aa.b → aQ)
Native 层
1 | 技术: |
4. 重打包检测 (EnumC0539aa.r → C0559au)
Native 层
1 | 技术: |
5. Hooking 框架检测 (EnumC0539aa.i → ay)
Native 层
1 | 技术 (ay 存储 bool + 5个字符串 = 框架名/路径/版本/hash/签名): |
IDA 关键地址: sub_16E2A0 (GotVerifyInfo 验证), sub_16E764 (GOT 二次验证)
6. 屏幕叠加/录屏检测 (EnumC0539aa.h → C0573o)
Native 层 + Java 代理
1 | 技术: |
IDA 关键地址: sub_17196C (ScreenMirroringBlock 初始化), sub_171AFC (布局检测)
7. 代码追踪器检测 (EnumC0539aa.q → aG)
Native 层 — 核心 JIT 检测引擎
1 | 函数: DoCodetracerDetection (sub_26B680) + CodetracerDetection (sub_26BD20) |
8. 模拟器检测 (EnumC0539aa.n → C0564f)
Native 层
1 | 技术 (C0564f 存储 bool + int模拟器类型码): |
9. 无障碍服务检测 (EnumC0539aa.o → aB)
Java 层 + Native 层
1 | 技术 (aB 存储 2×bool: 是否开启 + 是否恶意): |
IDA 关键地址: protobuf AllowedActivitiesForScreenreader @ 0x34796, xrefs 在 0x42323
10. 篡改检测 (EnumC0539aa.g → K)
Native 层
1 | 技术 (K 存储 str证书hash + 2×bool): |
11. 虚拟环境检测 (EnumC0539aa.l → S)
Native 层
1 | 技术 (S 存储 2×bool, d()=任一触发): |
12. 恶意Activity检测 (EnumC0539aa.k → T)
Java + Native 层
1 | 技术 (T 存储 ComponentName + 2×str): |
13. SSL Pinning/证书验证 (EnumC0539aa.c → C0540ab)
Native 层 (LibreSSL)
1 | 技术 (C0540ab 存储 bool): |
14. 已安装App扫描 (EnumC0539aa.p → C0549ak)
Java 层 (x1.b 回调处理)
1 | 技术 (C0549ak 存储 8字段对象列表): |
15. 设备完整性检测 (EnumC0539aa.d → C0572n)
Java + Native 层
1 | 技术 (C0572n 存储 bool): |
16. 密钥存储检测 (EnumC0539aa.j → W)
Java + Native 层
1 | 技术 (W 存储 bool): |
17. 恶意App哈希匹配 (EnumC0539aa.a → aD)
Java 层 (jtqupujl.aM + x1.b)
1 | // jtqupujl.aM.a(context, packageManager, list, str) |
Native 层核心反检测对抗技术
1. JIT SVC 引擎 (最关键)
1 | sub_26B680 (DoCodetracerDetection): |
2. 字符串全加密
1 | 所有敏感字符串 (frida/xposed/su/magisk/com.topjohnwu 等) |
3. GOT 完整性验证
1 | sub_16E2A0 (GotVerifyInfo): |
4. 41个 Protobuf 配置消息
1 | promon.pbi.* 完整列表: |
说些什么吧!