第9章 问题排查

9.1 “Failed to spawn”

原因与解决方案

原因解决方案
SELinux 阻止adb shell "su -c setenforce 0"
版本不匹配pip install frida==17.9.11 确保与 server 一致
32位应用+64位server同时推送 arm 和 arm64 版本
Zygote 问题 (Android 12+)升级到 Frida 17.6.0+(轻量级 Zygote hook)
App spawn 保护改用 attach 模式
Android 14+ 新进程模型17.9.10 修复了自定义进程的 spawn 匹配
仅 64 位设备 spawn 慢17.9.0+ 自动跳过 32 位 helper
# 验证版本匹配
frida --version        # 客户端
adb shell "/data/local/tmp/frida-server --version"  # 服务端
 
# 使用 attach 替代 spawn
frida -U --no-pause -p $(pidof com.target.app) -l script.js

17.6.0+ Zygote Hook 改进

Frida 17.6.0 完全重写了 Android Zygote hook 机制:

  • 不再注入代码到 Zygote 进程内部
  • 改为通过 /proc/$pid/mem 扫描 + 920 字节轻量 payload
  • 使用 abstract UNIX socket 通信
  • 消除了线程停止/重启和文件描述符泄漏问题

如果遇到 spawn 问题,确保升级到 17.6.0+。


9.2 “Process crashed”

常见原因

1. Hook 时类未加载

// ❌ 错误: 类可能还未加载
Java.perform(function() {
    var MyClass = Java.use('com.dex.DynamicClass');  // 可能崩溃
});
 
// ✅ 正确: 等待 ClassLoader
Java.perform(function() {
    Java.enumerateClassLoaders({
        onMatch(loader) {
            try {
                loader.loadClass("com.dex.DynamicClass");
                Java.classFactory.loader = loader;
                // 现在安全 hook
            } catch(e) {}
        },
        onComplete() {}
    });
});

2. 重载选择错误

// 先列出所有重载
var methods = Java.use("com.target.Class").targetMethod.overloads;
methods.forEach(function(m) {
    console.log(m.returnType.name + " " +
        m.argumentTypes.map(t => t.name).join(', '));
});

3. Native hook 参数类型错误

// 确保使用正确的 NativePointer 类型和大小
// ARM64: 指针 8 字节,int 4 字节

4. 脚本异常导致进程崩溃

// 全局异常处理
Process.setExceptionHandler(function(details) {
    console.log("异常: " + JSON.stringify(details));
    return true;  // 已处理,不崩溃
});

5. NativeCallback 返回未初始化数据(17.9.9 修复)

// ❌ 旧版本中可能导致崩溃:NativeCallback 返回值包含未初始化栈数据
// ✅ 17.9.9+ 修复了 struct 返回和未初始化栈数据问题
var callback = new NativeCallback(function() {
    return [0, 0, 0];  // 确保所有字段初始化
}, ['int', 'int', 'int'], ['pointer']);

6. Transsion(传音)ROM 初始化崩溃(17.8.0 修复)

// 某些基于 Transsion 的 ROM 需要 Looper.prepareMainLooper()
// 17.8.0+ 已自动处理,旧版本可能在这些设备上崩溃
// 解决方案:升级到 17.8.0+

9.3 “Unable to find application”

原因解决方案
包名错误adb shell pm list packages | grep target
App 未运行 (attach 模式)改用 frida -U -f com.target.app spawn
多用户/工作配置frida -U -f com.target.app --aux='uid=10'
frida-server 未运行adb shell "ps -e | grep frida"
USB 调试问题adb kill-server && adb start-server
带作用域的包名 (17.9.10)确保 @ 符号正确转义

9.4 “PTRACE_ATTACH failed”

# 禁用 Magisk Hide / Zygisk DenyList
# 确保 frida-server 以 root 运行
adb shell "su -c /data/local/tmp/frida-server -D"
 
# 检查 ptrace_scope
adb shell "cat /proc/sys/kernel/yama/ptrace_scope"
# 0 = 允许, 1 = 仅父进程, 2 = 仅 admin, 3 = 禁止
 
# Android 14+: 检查是否有 seccomp 限制
adb shell "su -c cat /proc/$(pidof com.target.app)/status | grep Seccomp"

9.5 “Script is destroyed”

目标进程退出了。解决方案:

  • 使用 spawn 模式 frida -U -f
  • 添加 --no-pause 参数
  • 监听 session.on('detached') 事件做重连
// Python 客户端自动重连
import frida
import time
 
def on_detached(reason, crash):
    print(f"[!] 断开: {reason}")
    if reason == 'process-terminated':
        time.sleep(1)
        reattach()
 
def reattach():
    device = frida.get_usb_device()
    pid = device.spawn(['com.target.app'])
    session = device.attach(pid)
    session.on('detached', on_detached)
    # ... 加载脚本
    device.resume(pid)

9.6 “Java.use: class not found”

类可能由非默认 ClassLoader 加载:

Java.perform(function() {
    Java.enumerateClassLoaders({
        onMatch(loader) {
            try {
                loader.loadClass("com.target.ObfuscatedClass");
                Java.classFactory.loader = loader;
                console.log('[*] 找到正确的 ClassLoader');
 
                // 现在可以 Java.use
                var MyClass = Java.use('com.target.ObfuscatedClass');
            } catch(e) {}
        },
        onComplete() {}
    });
});

9.7 连接问题排查清单

# 1. 确认设备连接
adb devices
 
# 2. 确认 frida-server 运行
adb shell "ps -e | grep frida"
 
# 3. 确认端口正常(默认 27042)
adb shell "netstat -tlnp | grep 27042"
 
# 4. 确认版本一致(17.9.11)
frida --version
adb shell "/data/local/tmp/frida-server --version"
 
# 5. 测试基本连接
frida-ps -U
 
# 6. 查看 server 日志
adb shell "su -c 'cat /data/local/tmp/frida-server.log'"
 
# 7. 重启 server
adb shell "su -c 'pkill -f frida-server'"
adb shell "su -c '/data/local/tmp/frida-server -D &'"
 
# 8. 使用自定义端口排除端口冲突(17.9.0+)
adb shell "su -c '/data/local/tmp/frida-server -l 0.0.0.0:31337 -D &'"
frida -H 127.0.0.1:31337 -U -f com.target.app
 
# 9. 使用 abstract socket(避免 TCP 端口扫描检测)
adb shell "su -c '/data/local/tmp/frida-server -l localabstract:frida-sock -D &'"

9.8 性能问题

症状: Hook 后应用明显卡顿

解决方案:

  1. 减少 hook 数量,只 hook 必要的函数
  2. 减少 console.log 调用(序列化开销大),改用 send()
  3. 缓存 args[] 值到局部变量
  4. 使用 Java.performNow() 替代 Java.perform()(不创建新线程)
  5. Stalker 中排除系统库: Stalker.exclude(libc)
  6. 使用 CModule 替代 JS 回调(性能提升 10-100 倍)
  7. 对于高频函数,考虑 NativeFunctionscheduling: 'exclusive' 选项

症状: 脚本加载很慢

解决方案:

  1. 拆分大脚本为按需加载的模块
  2. 使用 QJS 运行时 (--runtime=qjs) 替代 V8(内存更小)
  3. 避免在全局作用域做大量枚举
  4. 使用 Module.findSymbolByName() 替代全量枚举 + 过滤(17.9.11)

症状: Stalker 追踪导致极慢

解决方案:

  1. 排除不需要追踪的模块: Stalker.exclude(module)
  2. 调高 Stalker.trustThreshold(默认 1,可设为 2-3)
  3. 使用 onCallSummary 替代 onReceive 减少事件量
  4. 只在必要的代码段启用精细追踪

9.9 Android 14/15 特有问题

问题: SELinux 拒绝 frida-server 操作

Android 14+ 强化了 SELinux 策略:

# 查看拒绝日志
adb shell "su -c dmesg | grep avc | grep frida"
 
# 临时禁用(仅测试环境)
adb shell "su -c setenforce 0"
 
# 永久方案:使用 Magisk + 自定义 SEPolicy 模块

问题: frida-server 无法 spawn non-debuggable 应用

# 17.8.0+ 支持通过 ProcessControlService spawn non-debuggable 应用
# 确保 frida-server 以 root 运行
 
# 如果仍然失败,可尝试 gadget 注入方案
objection patchapk --source target.apk --gadget-version 17.9.11

问题: 匿名内存检测

# 17.8.2 修复了 setArgV0() 在匿名内存中被检测的问题
# 确保升级到 17.8.2+ 以避免此问题

问题: App 使用 Play Integrity API 检测环境

// Play Integrity 是服务端验证,无法纯客户端绕过
// 推荐方案:
// 1. Magisk + Shamiko(隐藏 root)
// 2. 使用 LSPosed 的 Hide My Applist 模块
// 3. 在已解锁的测试设备上禁用 GMS

9.10 版本升级注意事项(17.4.1 → 17.9.11)

关键变更

版本重要变更影响
17.5.0Swift 绑定重写为 async/awaitSwift 客户端需更新
17.6.0Zygote hook 轻量化重写Android spawn 更稳定
17.6.0frida-java-bridge 从核心移除Java hook 不受影响(已内置)
17.6.0Interceptor FORCE 标志可 hook 极小函数
17.8.0eBPF 系统调用追踪新增 frida-strace 工具
17.8.0frida-helper.dex 进程内执行减少兼容性问题
17.9.0control-endpoint 选项支持自定义端口/socket
17.9.0eBPF spawn gatingLinux spawn 更可靠
17.9.8Memory.alloc 可选保护参数精细内存控制
17.9.9NativeCallback struct 修复结构体返回更安全
17.9.11Darwin PAC 增强 + arm32 relocator 修复跨平台稳定性

升级步骤

# 1. 升级客户端
pip install frida==17.9.11 frida-tools==13.6.1
 
# 2. 下载对应版本 server
wget https://github.com/frida/frida/releases/download/17.9.11/frida-server-17.9.11-android-arm64.xz
unxz frida-server-17.9.11-android-arm64.xz
 
# 3. 部署到设备
adb push frida-server-17.9.11-android-arm64 /data/local/tmp/frida-server
adb shell "su -c 'chmod 755 /data/local/tmp/frida-server'"
 
# 4. 停止旧版本并启动新版本
adb shell "su -c 'pkill -f frida-server'"
adb shell "su -c '/data/local/tmp/frida-server -D &'"
 
# 5. 验证
frida --version  # 应显示 17.9.11
frida-ps -U     # 应正常列出进程

9.11 最佳实践总结

实践说明
版本严格匹配client/server/gadget 三者版本必须完全一致 (17.9.11)
先注册再 loadscript.on('message', ...)script.load() 之前
spawn 后 resume否则进程永远挂起
引用防 GCMemory.alloc 的结果存到 this.xxx 或模块级变量
异常处理总是注册 session.on('detached')
重载确认hook 前先列出 .overloads 确认签名
ClassLoader找不到类时枚举 ClassLoader
最小 hook只 hook 必要的,完成后 detachAll()
CModule 优先高频函数用 CModule 替代 JS 回调
符号直接查找findSymbolByName 替代全量枚举过滤
自定义端口生产环境使用非默认端口或 abstract socket
eBPF 追踪系统调用分析优先用 frida-strace