【Frida Android】基础篇2:Frida基础操作模式详解
文章目录
- 概述
- 1 辅助工具准备
- 1.1 JADX(反编译工具)
- 2 CLI模式:纯JS脚本+命令行执行
- 2.1 步骤1:编写Frida JS脚本
- 2.2 步骤2:命令行执行脚本
- 2.3 步骤3:退出与终止进程
- 3 Frida 17版本重要变更
- 3.1 变更背景:从“捆绑”到“独立”
- 3.2 对用户的影响
- 4 RPC模式:Python加载JS脚本
- 4.1 环境准备
- 4.2 编写脚本
- 4.2.1 JS脚本(hook.js)
- 4.2.2 Python脚本(run.py)
- 4.3 执行流程
- 总结
⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。
概述
Frida是一款功能强大的动态插桩框架,通过编写脚本可对进程内存中的对象方法进行监视、修改或替换。其核心操作模式分为两种:
- CLI(命令行)模式:直接通过命令行将JavaScript脚本注入进程;
- RPC模式:通过Python加载JavaScript脚本并注入进程,脚本实际运行逻辑仍由JavaScript实现。
本文将详细介绍两种模式的操作流程、辅助工具及Frida 17版本的重要变更。
本章示例应用的链接:
https://pan.baidu.com/s/16EE2XE-OZS_xBRPlWUODbw?pwd=n2vb
提取码: n2vb
使用APK:hwyysc_252571.apk
1 辅助工具准备
1.1 JADX(反编译工具)
JADX用于反编译APK,获取目标应用的包名、类名及函数信息,是Frida脚本编写的基础工具。
- 官方下载:https://github.com/skylot/jadx/releases
- 推荐版本(Windows):jadx-gui-1.5.3-win.zip
使用示例:通过JADX反编译目标APK,可查询应用包名和函数关键字,如下图所示:
2 CLI模式:纯JS脚本+命令行执行
直接编写JavaScript脚本,通过frida
命令行工具注入目标进程,适用于简单的Hook场景。
2.1 步骤1:编写Frida JS脚本
以Hook华为应用市场(com.huawei.appmarket
)的MainActivity
类的onCreate
方法为例,脚本功能为打印方法调用日志及参数:
// hook.js
Java.perform(function () {// 获取目标类(替换为实际应用的类名)const MainActivity = Java.use('com.huawei.appmarket.MainActivity');// Hook onCreate 方法MainActivity.onCreate.implementation = function (savedInstanceState) {console.log('[*] MainActivity.onCreate 被调用');// 打印参数(savedInstanceState 是 Bundle 类型)console.log('参数: savedInstanceState =', savedInstanceState);// 调用原方法this.onCreate(savedInstanceState);};
});
2.2 步骤2:命令行执行脚本
-
环境准备:确保设备已通过
adb devices
识别,且frida-server
已在设备上后台运行(./frida-server &
); -
安装目标应用:在模拟器中安装
com.huawei.appmarket
APK,如下图所示:
-
执行命令:
# -U:连接USB设备;-f:启动目标应用(由Frida控制);-l:加载JS脚本 frida -U com.huawei.appmarket -l hook.js
-
查看结果:当应用启动时,
onCreate
方法被调用会输出日志,如下图所示:
2.3 步骤3:退出与终止进程
通过以下命令退出Frida并终止目标进程:
# 输入%暂停Hook
%# 退出Frida
exit
操作效果如下图:
3 Frida 17版本重要变更
Frida 17.0.0版本对运行时桥接机制进行了重大调整,核心变化为“解耦Runtime Bridges”和“移除Legacy API”,需重点关注。
3.1 变更背景:从“捆绑”到“独立”
- 旧版本(<17.0.0):
frida-java-bridge
(Android Java交互)等桥接模块内置在GumJS运行时中,脚本可直接使用Java.perform()
等方法,无需额外配置。 - 17.0.0版本:桥接模块从GumJS中拆分,不再默认加载,原因包括:
- 减少冗余代码(如纯Native Hook场景无需加载Java桥接);
- 支持桥接模块独立迭代;
- 便于社区扩展第三方桥接(如Rust、Kotlin)。
3.2 对用户的影响
- 自动加载场景:使用
frida
命令行工具(frida-tools 14.0.0+
)时,桥接模块会默认加载,CLI模式脚本可正常运行。 - 手动加载场景:通过Python API(
frida-python
库)加载脚本时,需手动引入桥接模块,否则会报ReferenceError: 'Java' is not defined
错误。
4 RPC模式:Python加载JS脚本
RPC模式通过Python控制脚本注入流程,适用于复杂场景(如动态参数传递、结果处理)。因Frida 17版本变更,需额外准备Node.js环境。
4.1 环境准备
-
安装Node.js:https://nodejs.org/zh-cn/download;
-
安装依赖(仅开发/编译阶段需要):
项目目录下执行:npm install frida-java-bridge --save-dev # Java桥接模块 npm install frida-compile --save-dev # 脚本编译工具 npm install @types/frida-gum --save-dev # 类型定义
-
目录结构:
-
配置package.json:添加编译命令,用于将JS脚本编译为可被Python加载的格式:
{"private": true,"main": "js/hook.js","scripts": {"build": "frida-compile js/hook.js -o js/compiled_hook.js","watch": "frida-compile js/hook.js -o js/compiled_hook.js -w", # 实时编译"prepare": "npm run build"},"devDependencies": {"@types/frida-gum": "^19.0.1","frida-compile": "^19.0.4","frida-java-bridge": "^7.0.8"} }
4.2 编写脚本
4.2.1 JS脚本(hook.js)
功能:遍历com.huawei.appmarket
包下所有类,查找并打印getString
方法信息:
import Java from 'frida-java-bridge'; // 手动引入Java桥接Java.perform(function () {// 获取所有已加载的类var classes = Java.enumerateLoadedClassesSync();// 遍历类,筛选目标包下的类classes.forEach(function (className) {if (className.startsWith("com.huawei.appmarket")) {try {var clazz = Java.use(className);var methods = clazz.class.getDeclaredMethods();// 查找getString方法methods.forEach(function (method) {if (method.getName() === "getString") {console.log(`Found getString method in class: ${className}`);console.log(`Method signature: ${method.toString()}`);}});} catch (e) {// 忽略无法加载的类}}});
});
4.2.2 Python脚本(run.py)
功能:连接设备、启动进程、加载并注入编译后的JS脚本:
import frida
import sys
import timedef on_message(message, data):"""处理JS脚本发送的消息"""if message['type'] == 'send':print(f"[Hook 日志] {message['payload']}")elif message['type'] == 'error':print(f"[错误] {message['stack']}")# 目标应用包名
PACKAGE_NAME = "com.huawei.appmarket"def main():try:# 连接USB设备device = frida.get_usb_device(timeout=10)print(f"已连接设备:{device.name}")# 启动目标进程并恢复(等待初始化)print(f"启动进程 {PACKAGE_NAME}...")pid = device.spawn([PACKAGE_NAME])device.resume(pid)time.sleep(2) # 等待Java环境就绪# 附加到进程并加载脚本process = device.attach(pid)print(f"已附加到进程 PID: {pid}")# 这里的路径修改为你们自己的 js 文件路径和配置的名称with open("./js/compiled_hook.js", "r", encoding="utf-8") as f:js_code = f.read()script = process.create_script(js_code)script.on('message', on_message)script.load()print("JS 脚本注入成功,开始监控...(按 Ctrl+C 退出)")# 阻塞等待sys.stdin.read()except frida.TimedOutError:print("未找到USB设备")except frida.ProcessNotFoundError:print(f"应用 {PACKAGE_NAME} 未安装")except FileNotFoundError:print("未找到 js 脚本,请检查路径")except Exception as e:print(f"异常:{str(e)}")finally:if 'process' in locals():process.detach()print("程序退出")if __name__ == "__main__":main()
4.3 执行流程
-
实时编译JS脚本:在根目录执行以下命令,监听脚本变化并自动编译:
npm run watch
效果如下图:
-
启动frida-server:在设备端执行:
adb shell su cd /data/local/tmp ./frida-server &
-
运行Python脚本:新开终端执行:
python run.py
执行效果如下图:
总结
本文介绍了Frida的两种核心操作模式:
- CLI模式:通过命令行直接注入JS脚本,操作简单,适用于快速调试,Frida 17+版本中桥接模块自动加载,无需额外配置;
- RPC模式:通过Python控制注入流程,灵活性更高,适用于复杂场景,但Frida 17+版本需手动引入桥接模块并编译脚本。
此外,Frida 17版本的“解耦Runtime Bridges”变更需重点关注,避免因桥接模块未加载导致的脚本错误。通过JADX反编译获取目标应用信息,是编写有效Frida脚本的前提。掌握这两种模式,可满足大部分动态插桩需求。