ksufrida 调试环境搭建与踩坑记录(小白学习记录,大佬轻喷)
目标 App: com.aiyu.kaipanla(爱加密加固壳 + VMP)
设备: Realme RMX3850 / Android 16 (API 36) / KernelSU
最终结论: Frida 17 完整调试能力已打通(Java 桥 + Native + 页面获取)
一、核心突破:Frida 17 的 Java 桥架构变更
1. 现象
通过 ksufrida/rusda/florida 等所有方式 attach 后,脚本里 typeof Java 恒为 undefined,
Java.perform() 直接报 ReferenceError: 'Java' is not defined。
2. 排查过程(排除了多个错误方向)
| 排查方向 |
结论 |
| gadget 被裁剪? |
❌ 官方/rusda/ksufrida gadget 与官方版仅 545 字节字符串混淆差异,非裁剪 |
| PC 端 frida 版本不匹配? |
❌ 17.9.1/17.15/17.17 全试过,都无 Java |
| 目标进程无 JVM? |
❌ JNI_GetCreatedJavaVMs 返回 JavaVM,ART 就绪 |
| 加固壳干扰? |
❌ 连 com.android.launcher 等无加固应用也 Java=undefined |
| frida-core 缺 Java 桥? |
❌ _frida.pyd 118MB,大小正常(字符串被压缩找不到) |
3. 真正根因(官方文档确认)
Frida 17.0.0 起,Java/ObjC/Swift 桥不再随 GumJS 运行时捆绑。(deepseek知识库可能还没更新,导致一直没发现)
用户必须显式引入 frida-java-bridge 并编译进脚本:
frida-create -t agent
npm install
npm install frida-java-bridge
import Java from "frida-java-bridge";
frida-compile agent/index.ts -o _agent.js -c
加载编译后的 _agent.js(而不是直接写 JS),Java 桥即生效。
4. 验证(目标 App 实际运行)
[+] Java bridge OK, pid=15564
[+] Java.perform running
[+] ActivityThread = android.app.ActivityThread@f3e90be
[CURRENT] com.yzj.kaipanh.newindex.ui.main.MainActivity
[INTENT] Intent { ... cmp=com.aiyu.kaipanla/com.yzj.kaipanh.newindex.ui.main.MainActivity }
Frida 17 完整能力清单(全部验证通过):
- Java.perform / Java.use / 方法 hook / 字段访问 / 对象创建 / Java.choose
- Native Interceptor hook
- 内存操作 / 模块枚举
- 获取当前 Activity(ActivityThread.mActivities 反射)
二、ksufrida 连接与端口
1. 实际端口
2. 连接方式
import frida
d = frida.get_device_manager().add_remote_device("127.0.0.1:62333")
s = d.attach("Gadget")
3. 注入前置条件
- ksufrida 模块在 KernelSU 中启用(
/data/adb/modules/ksufrida/disable 不存在)
- Zygisk Next 正常工作(
module.prop 描述显示 ✅zygote)
- 目标 App 进程由 zygote fork 后 ksufrida 注入
- 端口 62333 出现才说明注入成功
三、踩过的坑(重要!)
坑 1:child_gating inject 模式导致点击卡死闪退
现象:App 每次点击就卡死,Input dispatching timed out ANR。
根因:child_gating.mode: "inject" 在子进程里 inject_lib() → dlopen gadget,
与主线程的 dlopen 竞争 linker 全局锁。gadget 构造器在 poll 等待时不释放锁,
主线程任何 dlopen(如触摸事件触发的 libinput.so)永久阻塞 → ANR。
ANR trace 关键帧:
主线程: dlopen_ext -> MutexLockWithTimeout (等锁)
另一线程: __dl_do_dlopen -> call_constructors -> libsecmon.so -> poll (持锁不释放)
解决:config.json 里 child_gating.enabled: false。
"child_gating": { "enabled": false, "mode": "freeze", "injected_libraries": [] }
坑 2:Zygisk Next 崩溃自动停止
现象:重启后 ksufrida 不注入(62333 无监听)。
根因:module.prop 描述显示 [❌ Stop zygisk due to crash——Zygisk Next 检测到
zygote 崩溃后自动禁用 zygisk 功能。
解决:重启手机(让 zygote 重新 fork,Zygisk Next 重新加载模块并恢复)。
坑 3:LSPosed 与 ksufrida 冲突
现象:启用 ksufrida 后 LSPosed 模块不注入(主进程 maps 无 lspd)。
根因:child_gating 的 kill 模式会杀 fork 出的子进程(含 LSPosed companion)。
解决:关闭 child_gating 后两者可共存(但通常只启用其一,避免 Zygisk 负担)。
坑 4:sub_5E1B0 内核 hook 能挡检测但 frida attach 超时
现象:用 xiaojianbang_hook 对 libexec.so+0x5E1B0 设 --replace-ret 0,
进程存活了,但 frida attach 报 TimedOutError。
根因:HWBP(perf 硬件断点)与 frida 的 ptrace STOP 冲突。
结论:该路径不可行,最终靠 ksufrida Zygisk 注入解决。
坑 5:rusda/florida attach 已运行进程会被壳 SIGKILL
现象:attach 报 ProcessNotFoundError / target terminated with signal 9。
根因:爱加密壳检测 attach 事件(TracerPid / ptrace)后自杀。
spawn 模式:能 attach 成功存活数秒,但 agent 无 Java 桥(回到坑 Frida17 架构)。
结论:传统 frida-server 路径(rusda/florida)不适合此壳,用 ksufrida 即可。
坑 6:Windows PowerShell 批量改文件导致中文乱码
现象:用 Set-Content -Encoding UTF8 批量替换 package 名后,
java 源码中文注释变乱码,编译报非法字符。
根因:PowerShell 5.1 的 UTF8 编码与 UTF-8 无 BOM 兼容问题。
解决:从备份恢复源码,用 Python 写文件(open(..., encoding='utf-8'))。
坑 7:I 级日志不进 logcat
现象:HookLog.i() 的日志在 logcat 里看不到。
根因:logcat 缓冲/优先级过滤,I 级日志被丢弃。
解决:HookLog 同时写文件 /sdcard/Android/data/com.aiyu.kaipanla/files/kpl_hook.log,
页面追踪日志都从文件读。
四、最终工作架构
KernelSU
├─ Zygisk Next (✅ 正常)
│ └─ ksufrida (启用, child_gating 关闭)
│ └─ libsecmon.so (frida-gadget 17.17.0, 监听 0.0.0.0:62333)
└─ KPatch-Next + xiaojianbang-stealth-hook.kpm (内核 KPM, 可选辅助)
PC 端
└─ frida 17.9.1/17.17.0 + frida-java-bridge bundle
└─ adb forward 62333 -> attach("Gadget") -> Java 桥全可用
关键文件
| 文件 |
用途 |
frida-java-bridge/agent/index.ts |
Java 桥 agent 源码 |
frida-java-bridge/_agent.js |
编译后的 bundle(加载它才有 Java) |
run_frida.py |
连接 ksufrida 并加载 Java 桥 bundle |
run_java_bridge.py |
同上(更通用,可指定端口/脚本) |
/data/local/tmp/libsec/config.json |
ksufrida 配置(child_gating 必须 false) |
五、复现步骤速查
adb shell "cat /data/adb/modules/zygisksu/module.prop | grep description"
adb shell "ls /data/adb/modules/ksufrida/disable"
adb shell "am start -n com.aiyu.kaipanla/com.yzj.kaipanh.newindex.ui.main.MainActivity"
adb shell "ss -tln | grep 62333"
adb forward tcp:62333 tcp:62333
python run_frida.py
六、附录:为什么不能直接写 JS 而要用 TS + frida-compile
Frida 17 的脚本运行时(QuickJS)不内置 require(require is not defined)。
import Java from "frida-java-bridge" 必须由 frida-compile(bundle 打包器)
在编译期把 Java 桥代码内联进 _agent.js。所以:
- 不能用纯 JS 直接写
Java.perform
- 必须用 TS +
npm install frida-java-bridge + frida-compile 编译
(注:frida-tools 自带的 frida REPL 和 frida-trace 内置三个桥,
可直接 frida -l script.js,但 Python API 的 create_script 需要预编译 bundle。)
ksufrida:ksufrida仓库链接
小白一枚,第一次发帖,这次工程花了不少时间,也多亏有AI相助,虽然踩了不少坑但也学习了不少。
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。