学习Frida脚本的编写
Frida脚本的概念
FRIDA脚本
就是利用FRIDA
动态插桩框架,使用FRIDA
导出的API
和方法,对内存空间里的对象方法进行监视、修改或者替换的一段代码。FRIDA
的API
是使用JavaScript
实现的,所以我们可以充分利用JS
的匿名函数的优势、以及大量的hook
和回调函数的API。如果不了解匿名函数,可以先简单了解一下,相信对你编写Frida脚本会有帮助。
举一个最简单的例子
1 | function main(){ |
这段代码的作用是在 Android 应用程序的 Java 虚拟机中执行一个函数,该函数将在 Frida 控制台输出 "hello world"。
控制台运行
1 | frida -U -l hello-world.js android.process.media |
“-U”表示使用USB连接到设备,而不是通过网络连接;”-l”表示指定要加载的JavaScript脚本文件;”android.process.media”是目标进程的名称
解释一下这段代码,
- 首先是
function main() { ... }
是javascript中定义函数的语法,函数名为main。 Java.perform(function() { ... });
是Frida中的一个重要函数,它接受一个函数作为参数,在被Frida Hook的Java虚拟机中执行。在这个函数内部,可以使用Frida提供的API接口来进行动态分析、修改、拦截等操作。console.log("hello world");
: 这是 JavaScript 中的输出语句,用于在 Frida 控制台输出信息。在这里,它将输出字符串 “hello worldsetImmediate(main)
: 这是 JavaScript 中的一个函数,用于在当前 JavaScript 事件循环的下一个循环迭代中执行指定的函数。在这里,它用于在当前 JavaScript 执行栈结束后立即调用main
函数。
进阶操作
了解了Frida如何进行基本的使用,接下来就可以尝试使用一些API函数进行操作。
枚举所有加载的类
1 | function main(){ |
保存并执行
可以得到如下结果
太多了只截取了最后一段
解释一下这段代码:
Java.enumerateLoadedClasses({ ... })
: 这是 Frida 提供的一个方法,用于枚举当前已加载的所有类。它接受一个 JavaScript 对象作为参数,该对象包含两个属性:onMatch
和onComplete
onMatch: function(_className) { ... }
: 这是一个回调函数,用于处理每个匹配到的类名。在每次找到一个类名时,这个函数会被调用。在这个函数中,类名存储在_className
参数中,并通过console.log
输出到 Frida 控制台onComplete: function() { ... }
: 这也是一个回调函数,当所有类都被枚举完毕时调用。在这个函数中,通过console.log
输出一条消息表示类枚举过程完成
定位目标类
我们既然可以获取到加载的所有类,也可以获取指定类。假如我们需要获取有关蓝牙的某个类,代码如下:
1 | function main(){ |
这里不再赘述代码的其他部分,只说onMatch函数的判断
instance
是通过Java.enumerateLoadedClasses
获取到的类,代表一个完整类名
split(".")[1]
是JavaScript的字符串方法,用于按照分隔符将字符串进行分割,因为类名多是以"."
进行命名,所以将"."
作为分割符使用,[1]
则是JavaScript 数组索引操作符,用于获取数组中指定索引位置的元素。在这里,我们获取分割后的字符串数组的第二个元素,即索引为1的元素。
打印类的实例
在我们定位到目标类后,就可以打印想要研究的类的实例了
代码:
1 | function main(){ |
运行
1 | frida -U -l hello.js com.android.bluetooth |
枚举所有方法
使用java.use()
获取所有方法
1 | function main() { |
控制台命令
1 | frida -U -l hello.js com.android.bluetooth |
获取了方法,接下来就是对方法的各种修改拦截了。