Frida 17 以后 Python API 跑旧版 JS 报 Java is not defined?一行直接恢复 Frida 16 体验
前言
如果你最近把 Frida 升级到了 17.x,然后还在用 Python API 直接注入老式 JS 脚本,大概率已经见过下面这个错误:
python
{'type': 'error', 'description': "ReferenceError: 'Java' is not defined", 'stack': "ReferenceError: 'Java' is not defined\n at (/script1.js:3)"}
最典型的场景就是这种老代码:
python
import frida
session = device.attach(pid)
script = session.create_script(source)
script.load()
然后 source 里还是传统写法:
javascript
Java.perform(function () {
var Activity = Java.use("android.app.Activity");
console.log(Activity);
});
在 Frida 16 时代,这种写法基本没什么问题。
但从 Frida 17 开始,桥接逻辑已经和以前不一样了,很多人一升级就直接踩坑。
所以我专门做了一个兼容库:frida-legacy-compat
它的目标很简单:
- 不改你原来的 Python 注入习惯
- 不要求目标机器安装 Node.js
- 不要求你把旧脚本全面改造成 TypeScript / ESM
- 只需要多加一行
import frida_legacy_compat - 然后继续直接
session.create_script(source)
Frida 17 到底改了什么?
从 Frida 17 开始,旧版 bridge 不再像 Frida 16 那样,默认跟随 Python API 的 plain JS 工作流直接可用。
也就是说:
- 以前你写
Java.perform(...)就能跑 - 现在你直接
session.create_script(old_js),很可能就报:
javascript
ReferenceError: 'Java' is not defined
如果按 Frida 17 新方式走,通常会遇到这些问题:
- 需要改成 TypeScript / ESM 编译
- 需要处理 bridge 包安装
- 有时候还需要额外下载 bridge
- 对"只想继续用老 JS + Python 注入"的用户来说,链路明显变复杂了
对于习惯 Frida 16 风格工作流的人来说,这个变化确实不太友好。
我做的这个库能解决什么?
frida-legacy-compat 就是专门为这个问题做的。
它会在导入后自动 patch:
python
frida.core.Session.create_script()
补丁逻辑大概是这样:
- 检测你传入的脚本是不是旧版 bridge 风格
- 如果脚本里出现
Java./ObjC./Swift.等全局对象 - 自动准备 bridge
- 自动编译成 Frida 17 能接受的 bundle
- 最后再调用原始
create_script()
用户感知上就一句话:
你原来怎么写,现在基本还怎么写。
安装方式
pip
bash
pip install frida-legacy-compat
如果你想同时安装推荐范围内的 Frida:
bash
pip install 'frida-legacy-compat[full]'
uv
bash
uv add frida-legacy-compat
或者:
bash
uv add 'frida-legacy-compat[full]'
最核心的使用方式
你原来的代码可能是这样:
python
import frida
device = frida.get_usb_device()
session = device.attach("com.example.app")
source = """
Java.perform(function () {
var Activity = Java.use("android.app.Activity");
console.log(Activity);
});
"""
script = session.create_script(source)
script.load()
现在你只需要多加一行:
python
import frida
import frida_legacy_compat
device = frida.get_usb_device()
session = device.attach("com.example.app")
source = """
Java.perform(function () {
var Activity = Java.use("android.app.Activity");
console.log(Activity);
});
"""
script = session.create_script(source)
script.load()
就这么简单。
一个更直观的 Demo:前台应用弹 Toast
下面给一个最直观的 Android 示例:
通过 USB 连接设备,attach 当前前台应用,然后直接调用原生 Toast。
python
import time
import frida
import frida_legacy_compat
def on_message(message, data):
print(message)
device = frida.get_usb_device()
app = device.get_frontmost_application(scope="full")
session = device.attach(app.pid)
source = """
setImmediate(function () {
if (typeof Java === "undefined" || !Java.available) {
console.log("[toast-demo] Java bridge is not available");
return;
}
Java.performNow(function () {
var ActivityThread = Java.use("android.app.ActivityThread");
var Context = Java.use("android.content.Context");
var JavaString = Java.use("java.lang.String");
var Toast = Java.use("android.widget.Toast");
var app = ActivityThread.currentApplication();
if (app === null) {
console.log("[toast-demo] currentApplication() is null");
return;
}
Java.scheduleOnMainThread(function () {
var text = JavaString.$new("frida-legacy-compat OK");
var context = Java.cast(app.getApplicationContext(), Context);
Toast.makeText(context, text, Toast.LENGTH_SHORT.value).show();
console.log("[toast-demo] Toast shown");
});
});
});
"""
script = session.create_script(source)
script.on("message", on_message)
script.load()
time.sleep(5)
session.detach()
这个示例我自己已经用 PyPI 上发布的版本实际验证过,能够正常弹出 Toast。
这个库适合谁?
我觉得这类人会很需要:
- 已经有一堆 Frida 16 风格旧项目的人
- 习惯 Python 注入 + 直接写老式 JS 的人
- 不想给目标环境增加 Node.js 依赖的人
- 只想快速恢复生产力,不想全面重构现有脚本的人
当前兼容范围
目前这个库的版本策略是:
frida < 17:通常不需要本库17.0 <= frida < 17.2:不支持17.2 <= frida < 18:支持frida >= 18:当前默认视为未验证
也就是说,当前最适合的使用范围是:
text
Frida 17.2.x ~ 17.x
它和直接改写新式 Frida 工作流相比有什么区别?
如果你是新项目,或者准备长期完全拥抱 Frida 17 的新工作流,那直接按官方新的编译方式走也没问题。
但如果你是下面这种情况:
- 老代码很多
- 旧脚本积累多
- 只是想让 Python API 下的旧脚本继续跑
那我更建议直接用这个兼容库。
因为它的价值不是"更先进",而是:
更省事、更少改动、更接近原来的使用习惯。
项目地址
GitHub:
text
https://github.com/RYF5584/frida-legacy-compat
PyPI:
text
https://pypi.org/project/frida-legacy-compat/
最后
如果你也踩过下面这种坑:
javascript
ReferenceError: 'Java' is not defined
并且你只是想继续保持:
- Python attach
session.create_script(source)- 老式
Java.perform(...)
那这个库应该正好适合你。
如果你觉得这个项目有帮助,欢迎去 GitHub 点个 Star,也欢迎提 Issue 反馈兼容问题。