有些人可能已经注意到,Frida 最近新增了 Android 支持,让你能像在 Windows、Mac、Linux 和 iOS 上一样轻松地对代码插桩。这听起来很酷,但 Android 会运行大量 Java 代码,这意味着你只能观察这些代码产生的原生层副作用。当然,你可以使用 Frida 的 FFI API 自己进入虚拟机,但这些繁琐工作难道不该由 Frida 代劳吗?当然应该!
实际效果如下:
Dalvik.perform(() => {
const Activity = Dalvik.use('android.app.Activity');
Activity.onResume.implementation = function () {
send('onResume() got called! Let's call the original implementation');
this.onResume();
};
});Dalvik.perform() 会负责把线程附加到虚拟机;在来自 Java 的回调中则无需调用它。第一次以某个类名调用 Dalvik.use() 时,Frida 会查询虚拟机并即时构建 JavaScript 包装器。上例取得 Activity 类,用我们自己的版本替换其 onResume 实现,向运行在 Windows、Mac 或 Linux 计算机上的调试器发送消息后,再调用原始实现。你也可以完全不调用原始实现,而是模拟其行为;或者模拟错误场景:
Dalvik.perform(() => {
const Activity = Dalvik.use('android.app.Activity');
const Exception = Dalvik.use('java.lang.Exception');
Activity.onResume.implementation = function () {
throw Exception.$new('Oh noes!');
};
});这样,你就实例化了一个 Java Exception,并直接从 Activity.onResume 的 JavaScript 实现中将其抛出。
此版本还带来了一些运行时增强:
-
Memory.copy(dst, src, n):与 memcpy 相同 -
Memory.dup(mem, size):依次调用Memory.alloc()和Memory.copy()的简写 -
Memory.writeXXX():补齐与Memory.read()对应的方法:S8、S16、U16、S32、U32、S64、U64、ByteArray、Utf16String 和 AnsiString -
Process.pointerSize:让脚本更具可移植性 -
NativePointer实例现在提供方便的isNull()方法 -
NULL常量:无需到处写ptr("0") - 面向高级用户的
WeakRef.bind(value, fn)和WeakRef.unbind(id):前者监视value,在value被垃圾回收或脚本即将卸载时调用fn,并返回一个 ID,可将其传给unbind()进行显式清理。构建语言绑定时,这个 API 很有用,因为 JS 值不再需要后,必须释放原生资源。
尽情体验吧!
oleavr