1. Frida常用命令概览
Frida作为一款强大的动态代码插桩工具,其命令行接口是我们与目标进程交互的主要方式。在实际逆向工程和安全测试中,熟练掌握Frida命令就像外科医生熟悉手术刀一样重要。根据我多年移动安全审计的经验,80%的逆向工作都可以通过几个核心命令组合完成。
Frida命令主要分为三大类:
- 进程控制命令:用于启动、附加和枚举进程
- 脚本注入命令:核心功能实现的关键
- 设备管理命令:处理多设备场景
提示:所有Frida命令都支持
--help参数获取详细用法说明,这是最权威的参考文档。
2. 进程控制命令详解
2.1 进程枚举与附加
frida-ps是使用频率最高的基础命令,它的几个常用变体:
# 查看本机运行的所有进程 frida-ps # 查看USB连接的Android设备进程(需先adb连接) frida-ps -U # 查看模拟器进程(需配置好端口转发) frida-ps -R 127.0.0.1:7555实际工作中我经常遇到进程名模糊匹配的需求,这时可以结合grep使用:
frida-ps -U | grep -i wechat附加到目标进程有两种经典方式:
# 方式1:附加到已运行进程 frida -U -n com.example.app -l script.js # 方式2:重启应用并附加 frida -U -f com.example.app -l script.js踩坑记录:Android 10+系统需要注意SELinux限制,遇到附加失败时可以尝试
frida --runtime=enable启用非标准运行时。
2.2 进程控制参数
控制目标进程行为的几个实用参数:
# 不中断应用运行(适合后台hook) frida -U -n com.example.app --no-pause -l script.js # 启用子进程调试(对付多进程应用) frida -U -n com.example.app --enable-child-gating -l script.js # 设置超时时间(单位秒) frida -U -n com.example.app --timeout 30 -l script.js在分析银行类APP时,--enable-child-gating参数特别有用,可以捕获所有子进程的创建事件。
3. 脚本注入与管理
3.1 基础脚本加载
Frida的核心能力通过JavaScript脚本实现,加载方式直接影响执行效果:
# 加载单个脚本文件 frida -U -n com.example.app -l hook.js # 加载多个脚本(按顺序执行) frida -U -n com.example.app -l hook1.js -l hook2.js # 从URL加载脚本(适合团队协作) frida -U -n com.example.app -l https://example.com/hook.js我习惯将常用hook函数封装成模块,通过require()方式引入:
// utils.js module.exports = { hexdump: function(address, size) { // 内存dump实现 } }; // hook.js const utils = require('./utils.js'); utils.hexdump(ptr("0x1234"), 64);3.2 脚本生命周期控制
大型逆向工程中需要动态管理脚本:
# 启动时延迟加载脚本(等待特定时机) frida -U -n com.example.app --delay 5000 -l script.js # 交互式命令行模式 frida -U -n com.example.app在交互模式下,可以实时执行命令:
// 查看已加载脚本 Process.enumerateModules() // 动态加载新脚本 .load hook_new.js // 卸载脚本 .unload hook_old.js经验分享:使用
setTimeout()实现条件触发比--delay更灵活,可以监听特定事件后再执行hook。
4. 多设备管理技巧
4.1 设备枚举与选择
当同时连接多个设备时,需要明确指定目标:
# 列出所有可用设备 frida-ls-devices # 指定设备序列号连接 frida -D 123456789 -n com.example.app -l script.js常见设备类型标识:
-U:默认USB设备-R:远程TCP连接-D:指定设备ID
4.2 远程连接配置
分析模拟器或云真机时需要建立TCP连接:
# 在设备端启动frida-server adb shell /data/local/tmp/frida-server & # 端口转发 adb forward tcp:27042 tcp:27042 adb forward tcp:27043 tcp:27043 # 连接远程服务 frida -R -n com.example.app -l script.js在团队协作场景下,可以搭建Frida网关:
# 启动网关模式 frida-server -l 0.0.0.0:8888 # 客户端连接 frida -H 192.168.1.100:8888 -n com.example.app -l script.js5. 高级调试技巧
5.1 内存操作命令
// 读取内存(示例:读取0x1234开始的16字节) Memory.readByteArray(ptr("0x1234"), 16) // 写入内存(示例:修改字符串内容) Memory.writeUtf8String(ptr("0x5678"), "hacked") // 内存保护属性修改 Memory.protect(ptr("0x1000"), 4096, 'rwx')危险操作:直接修改内存可能引发崩溃,建议先用
Memory.protect()调整权限。
5.2 线程控制与异常处理
// 枚举线程 Process.enumerateThreads() // 线程挂起/恢复 const thread = Thread.findById(123) thread.suspend() thread.resume() // 设置异常回调 Process.setExceptionHandler(function(exception) { console.log("Exception caught:", exception); });5.3 文件系统访问
// 文件读写 const fd = File.open("/data/data/com.example.app/files/config.json", "r") const content = File.readAll(fd) File.close(fd) // 目录遍历 const dir = Dir.open("/data/data/com.example.app") let entry while ((entry = dir.next()) !== null) { console.log(entry.name) } dir.close()6. 实战问题排查指南
6.1 常见错误处理
问题1:Frida Server版本不匹配
Error: unable to connect to remote frida-server解决方案:
# 查看本地frida版本 frida --version # 下载对应版本的server wget https://github.com/frida/frida/releases/download/16.0.0/frida-server-16.0.0-android-arm64.xz # 推送到设备 adb push frida-server-16.0.0-android-arm64 /data/local/tmp/问题2:SELinux限制
Error: process is not responding解决方案:
adb shell su -c "setenforce 0" adb shell su -c "chmod 755 /data/local/tmp/frida-server"6.2 性能优化技巧
- 脚本预编译:
frida-compile hook.js -o hook_opt.js- 减少IPC调用:
// 反例:频繁跨进程调用 setInterval(() => { let value = Memory.readInt(ptr("0x1234")) }, 100) // 正例:本地缓存+批量处理 let cache = {} setInterval(() => { cache.value = Memory.readInt(ptr("0x1234")) }, 5000)- 使用Worker线程:
const worker = new Worker('worker.js') worker.postMessage({ cmd: 'start', target: ptr("0x1234") })7. 安全对抗与反检测
7.1 Frida特征隐藏
现代应用会检测Frida的存在,常见对抗手段:
// 修改frida-server端口 frida-server -l 127.0.0.1:9999 // 重命名server二进制文件 mv frida-server fs123 // 使用定制版frida git clone https://github.com/xxx/frida-modified7.2 反调试绕过
针对各类反调试技术的应对方案:
// 检测TracerPid const fd = File.open("/proc/self/status", "r") const content = File.readAll(fd) if (content.indexOf("TracerPid: 0") === -1) { // 被调试状态,进行伪装 Memory.writeUtf8String(ptr("/proc/self/status"), "TracerPid: 0\n") } // 检测ptrace Interceptor.attach(Module.findExportByName(null, "ptrace"), { onEnter: function(args) { if (args[0].toInt32() === PT_DENY_ATTACH) { this.returnValue = 0; } } })8. 扩展工具链集成
8.1 与逆向工具配合
IDA Pro集成:
# idascript.py import frida session = frida.attach("target") script = session.create_script(""" Interceptor.attach(ptr("%x"), { onEnter: function(args) { send(args[0].toInt32()); } }); """ % here()) script.on('message', on_message) script.load()GDB集成:
# 在GDB中连接frida target remote | frida -p 1234 -l gdb.js8.2 自动化脚本开发
基于Python的自动化框架示例:
import frida def on_message(message, data): print(message) device = frida.get_usb_device() pid = device.spawn(["com.example.app"]) session = device.attach(pid) with open("hook.js") as f: script = session.create_script(f.read()) script.on("message", on_message) script.load() device.resume(pid)9. 版本兼容性管理
9.1 版本匹配原则
Frida生态中三个关键组件需要版本一致:
- 本地frida-tools
- 设备端frida-server
- frida-python(如使用)
查看版本信息:
# 本地环境 frida --version pip show frida # 设备端 adb shell /data/local/tmp/frida-server --version9.2 多版本共存方案
使用pyenv管理多Python环境:
pyenv install 3.8.0 pyenv virtualenv 3.8.0 frida14 pyenv activate frida14 pip install frida==14.2.18 frida-tools==9.2.410. 实战案例:微信消息监控
结合上述命令实现一个完整案例:
// wechat_hook.js Java.perform(function() { const Message = Java.use('com.tencent.mm.modelmulti.i'); Message.a.overload('...').implementation = function() { const result = this.a.apply(this, arguments); console.log('WeChat message:', JSON.stringify(result)); return result; }; });执行命令:
frida -U -n com.tencent.mm -l wechat_hook.js --no-pause关键技巧:
- 使用
--no-pause避免干扰微信正常运行 - 通过
Java.perform确保在主线程执行 - 使用
overload处理重载方法