Frida 框架学习
一、环境搭建
frida框架分为两部分:
- 一部分是运行在系统上的交互工具frida CLI。
- 另一部分是运行在目标机器上的代码注入工具 frida-serve。
环境安装
#windows pip install frida pip install frida-tools getprop ro.product.cpu.abi #查看安卓CPU型号,然后去 https://github.com/frida/frida/releases 下载对应型号
之后,把文件上传到手机
adb push frida-server-12.2.25-android-arm64 /data/local/tmp/
chmod 755 frida-server-12.2.25-android-arm64
./frida-server-12.2.25-android-arm64
下面我们尝试一些常见的Hook手段
二、Hook 普通函数
比如这样一个APK文件
我们Hook my_activity 这个类中的 fun 函数
Frida python代码
import time import frida device = frida.get_usb_device() pid = device.spawn(["com.example.a11x256.frida_test"]) device.resume(pid) time.sleep(1) # Without it Java.perform silently fails session = device.attach(pid) with open("s1.js") as f: script = session.create_script(f.read()) script.load() # prevent the python script from terminating raw_input()
js代码
console.log("Script loaded successfully "); Java.perform(function x() { //Silently fails without the sleep from the python code console.log("Inside java perform function"); //get a wrapper for our class var my_class = Java.use("com.example.a11x256.frida_test.my_activity"); //replace the original implmenetation of the function `fun` with our custom function my_class.fun.implementation = function (x, y) { //print the original arguments console.log("original call: fun(" + x + ", " + y + ")"); //call the original implementation of `fun` with args (2,5) var ret_value = this.fun(2, 5); return ret_value; } });
这里是要Hook一个Java方法,首先使用
Java.use找到Java的类,然后调用方法的
implementation来实现Hook,提供一个回调函数,这个函数将覆盖原有的函数。
运行后可以看到消息被打印到了控制台上
我们也可以在命令行上通过 adb logcat | findstr Sum 命令查看系统消息
三、Hook 重载函数
jadx载入后代码如下:
可以看出,主函数调用了两个fun函数,一个是void fun(int,int) ,另一个是string fun (string x)
我们Hook的时候需要考虑到重载的问题,不然程序会报错
frida Python代码
import time import sys import frida def my_message_handler(message, payload): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message) device = frida.get_usb_device() pid = device.spawn(["com.example.a11x256.frida_test"]) device.resume(pid) time.sleep(1) # Without it Java.perform silently fails session = device.attach(pid) with open(r"D:\Java\Android\Frida\frida-android-examples-master\examples\2\s2.js") as f: script = session.create_script(f.read()) script.on("message", my_message_handler) script.load() # prevent the python script from terminating sys.stdin.read()
python代码没有太大变化,主要是js代码
js代码
console.log("Script loaded successfully "); Java.perform(function x() { console.log("Inside java perform function"); var my_class = Java.use("com.example.a11x256.frida_test.my_activity"); my_class.fun.overload("int", "int").implementation = function (x, y) { //hooking the old function console.log("original call: fun(" + x + ", " + y + ")"); var ret_value = this.fun(2, 5); return ret_value; }; var string_class = Java.use("java.lang.String"); my_class.fun.overload("java.lang.String").implementation = function (x) { //hooking the new function console.log("*************************************") var my_string = string_class.$new("My TeSt String#####"); console.log("Original arg: " + x); var ret = this.fun(my_string); console.log("Return value: " + ret); console.log("*************************************") return ret; }; });
可以看到 js代码的Hook函数多了 overload 这个函数...
四、主动调用类中的函数
这里有多种思路,比如我们可以创建一个新对象完成调用,或者我们也可以搜索内存中已有的对象进行调用,Java.choose函数就是查找对象的功能
(推荐使用内存中原有的对象,因为内存中的对象才是应用真实的应用使用的对象,自己创建对象的数据可能与应用当时实际使用的数据不一致
python代码
import time import frida def my_message_handler(message, payload): print (message) print (payload) device = frida.get_usb_device() pid = device.spawn(["com.example.a11x256.frida_test"]) device.resume(pid) time.sleep(1) # Without it Java.perform silently fails session = device.attach(pid) with open(r"D:\Java\Android\Frida\frida-android-examples-master\examples\3\s3.js") as f: script = session.create_script(f.read()) script.on("message", my_message_handler) script.load() command = "" while 1 == 1: command = input("Enter command:\n1: Exit\n2: Call secret function\nchoice:") if command == "1": break elif command == "2": script.exports.callsecretfunction()
js代码
console.log("Script loaded successfully "); var instances_array = []; function callSecretFun() { Java.perform(function () { if (instances_array.length == 0) { // if array is empty Java.choose("com.example.a11x256.frida_test.my_activity", { //choose 在堆上查找实例化的对象 //onMatch 对应的函数在命中一个实例的时候被调用,传入函数中的参数 instance 就是被命中的实例 onMatch: function (instance) { console.log("Found instance: " + instance); instances_array.push(instance) console.log("Result of secret func: " + instance.secret()); }, onComplete: function () { } //onComplete 函数会在所有实例遍历完毕之后被调用,可以做一些后续处理操作 }); } else {//else if the array has some values for (i = 0; i < instances_array.length; i++) { console.log("Result of secret func: " + instances_array[i].secret()); } } }); } rpc.exports = { callsecretfunction: callSecretFun //用于和 python 代码打交互 };
Java.use(className),动态获取className的类定义
Java.perform方法:当 js 附加到目标的进程中时被执行,运行其中定义的函数
Java.choose方法:通过完整类名,获取它的实例,从而对实例中的数据进行修改
onMatch 对应的函数在命中一个实例的时候被调用,传入函数中的参数 instance 就是被命中的实例
onComplete 函数会在所有实例遍历完毕之后被调用,可以做一些后续处理操作
上面的frida 脚本中python脚本和js脚本通过rpc.exports 打了个交互
代码中我们直接搜索内存中的对象并调用了 secret 函数
五、Hook apk系统函数
python代码
import time import frida def my_message_handler(message, payload): print (message) print (payload) if message["type"] == "send": # print message["payload"] data = message["payload"].split(":")[1].strip() script.post({"my_data": data}) # send JSON object print ("Modified data sent") device = frida.get_usb_device() pid = device.spawn(["com.example.a11x256.frida_test"]) device.resume(pid) time.sleep(1) session = device.attach(pid) with open(r"D:\Java\Android\Frida\frida-android-examples-master\examples\4\s4.js") as f: script = session.create_script(f.read()) script.on("message", my_message_handler) # register the message handler script.load() sys.stdin.read()
js脚本
console.log("Script loaded successfully "); Java.perform(function () { var tv_class = Java.use("android.widget.TextView"); tv_class.setText.overload("java.lang.CharSequence").implementation = function (x) { var string_to_send = x.toString(); var string_to_recv; send(string_to_send); // send data to python code recv(function (received_json_object) { string_to_recv = received_json_object.my_data }).wait(); //block execution till the message is received return this.setText(string_to_recv); } });
这里通过Hook android.widget.TextView 类中的 java.lang.CharSequence方法读取了文本框中的值
每次点击button按钮就会触发
参考:
六、一些函数或关键词
1、spawn函数: spawn模式,找到目标包名并重启,在进程创建时注入(js),与此同时,Frida还有一种操作APP的模式是attach,即应用运行过程中注入(js)到进程
2、overload函数,主要用于重载
3、Java.use(className),动态获取className的类定义
Java.perform方法:当 js 附加到目标的进程中时被执行,运行其中定义的函数
Java.choose方法:通过完整类名,获取它的实例,从而对实例中的数据进行修改
onMatch 对应的函数在命中一个实例的时候被调用,传入函数中的参数 instance 就是被命中的实例
onComplete 函数会在所有实例遍历完毕之后被调用,可以做一些后续处理操作
参考: