Frida 学习笔记
基本运用
frida -u com.example.test -l injection.js # 以spwan 形式启动
frida -Uf com.example.test -l injection.js # 以附加(attach)形式启动 , F表示从当前最顶层的app
(function frida_hook(){ Java.perform(function(){ // 创建 Java.use("com.example.lesson4one.MainActivity").fun.overload('int', 'int').implementation = function(arg1, arg2){ // 使用当前的 use 对象主动调用 fun 方法 var result = this.fun(arg1,arg2); // 打印堆栈当前对象的 fun 方法调用的 堆栈信息 console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); // 修改返回结果 return 800; } // 创建 Java.use("com.example.lesson4one.MainActity").fun.overload('java.lang.String').implementation = function (arg1){ var result = this.fun(Java.use('java.lang.String')).$new("NI HAO JAVA"); console.log("arg1, result", arg1, result); return Java.use('java.lang.String').$new("NI HAO JS"); } // 使用已存在的实例,若内存中不存在该实例会报错 Java.choose("com.example.lesson4one.MainActity", { // 这里的instance指的是上面choose的实例 onMatch: function(instance){ console.log("found instance :", instance); // 利用实例调用里面的secret方法 instance.secret(); }, onComplete: function(){ } }); // 静态直接调用,需要找到该静态方法的实例 var result = Java.use("com.example.lesson4one.MainActivity").secret2(); console.log(result); }) })() function invoke(){ Java.perform(function(){ Java.choose("com.example.test.MainActivity",{ onMatch: function(instacne){ console.log("found instacne ", instance); // 主动调用 console.log("invoke instance.a", instance.a()); }, onComplete: function(){ console.log("search completed ~ "); } }) }) } // 延迟调用 3s setTimeout(invoke, 3000);使用
frida-ps -Uf com.example.test -l injection.js
%resume
invoke()
使用Firda:构造数组、强制类型转换、注册接口实现方法、枚举、Map、
(function frida_middle(){ Java.perform(function(){ // hook 数组 Java.use("java.util.Arrays").toString.overload('[C').implementation = function(x){ var charArray = Java.array('char', ['一','去','二','三',里']); var result = this.toString(charArray); return Java.use('java.lang.String').$new(Java.array('char',['烟','村','四','五','家'])); }; // 强制类型转换 var juiceHandle = null; Java.choose("com.r0ysue.a0526printout.Juince",{ onMatch: function(instance){ console.log("found instance :", instance); console.log("filling energy,", instance.fillEnergy()); }, onComplete: function(){console.log("Search completed ~")} }) var watterHandle = Java.case(juiceHandle, Java.use("com.r0ysue.a0526printout.Water")); console.log("water invoke still ", waterHandle.still(waterHandle)); // 注册接口实现 var beer = Java.registerClass({ // 注册的类名 name: 'com.r0ysue.a0526printout.beer', // 需要实现的接口 包名 + 接口名 implements: [Java.use('com.r0ysue.a0526printout.liquid')], methods{ // 需要实现所有的方法,无参数则不需要传入,有参数就必须按照指定类型的参数进行传入 flow: function(){ console.log("look I'm beer ~"); return "taste good ~"; } } }); console.log("beer flow: ", beer.$new().flow()); // 使用枚举 Java.choose("com.r0ysue.a0526printout.Signal",{ onMatch: function(instance){ console.log("found instance: ", instance); console.log("invoke getDeclaringClass", instance.getDeclaringClass()); }, onComplete: function(){console.log("Search Completed ~ ")} }) // hook map Java.chooses("java.util.HashMap",{ onMatch: function(instance){ if(instance.toString.indexOf("ISBN") != -1){ console.log("found HashMap", instance); console.log("HashMap toString :", instance.toString()); } }, onComplete: function(){ console.log("Search completed ~"); } }) // hook map.put Java.use("java.util.HashMap").put.implementation = function(x ,y){ var result = this.put(x,y); console.log("x, y, result", x, y, result); } }); })()
Frida hook 方法的返回实例路径、枚举加载的class
(function(){ Java.perform(function(){ Java.choose("com.example.androiddemo.Activity.FridaActivity5",{ onMatch: function(instance){ // 一定要在调用过后才能看到class name console.log("found instance getDynamicDexCheck :", instance.getDynamicDexCheck().$className); }, onComplete: function(){ console.log("Search completed ~~"); } // 枚举加载的 class loaders 从内存中寻找 Java.enumerateClassLoaders({ onMatch: function(loader){ try{ if(loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")){ console.log("Succefully found loader ~", loader); Java.classFactory.loader = loader; } }catch(error){ console.log("found error", error); } }, onComplete: function(){ console.log("enum completed ~"); } }) }) }) })()
Frida hook 接口实现类
(function(){ Java.perform(function(){ Java.enumerateLoadedClasses({ "onMatch": function(className){ if(class.indexOf("com.example.androiddemo") < 0){ return; } var hookCls = Java.use(className); var interFaces = hookCls.clss.getInterfaces(); if(interFaces.length > 0){ console.log(className); for(var i in interFaces){ console.log("\t", interFaces[i].toString()) } } } }) }) })()
Frida rpc
import time import frida def my_message_handler(message, payload): print(message) print(payload) # method 1 # device = frida.get_usb_device() # method 2 # pid = device.spawn(["com.example.leeson4one"]) # device.resume # time.sleep(1) # session = device.attach(pid) # method 3 非标准连接 device = firda.get_device_manager().add_remote_device("192.168.1.102:9999") session = device.attach("com.example.lesson4one") with open("lesson7lesson4.js") as f: script = seesion.create_script(f.read()) script.on("message", my_message_handler) script.load() command = "" while True: command = input("Enter Command: ") if command == "1" break elif command == "2": script.exports.invokefunc()invoke js
function invoke(){ Java.perform(function(){ Java.choose("com.example.lesson4one.MainActivity",{ onMatch: function(instance){ console.log("found instance :", instance) console.log("found instance :", instance.secret()) }, onComplete: function(){ console.log("Search completed ~"); } }) }) } rpc.exports = { invokefunc: invoke }firda 传入 和 传出
lesson7sec.js
Java.perform(function(){ Java.use("android.widget.TextView").setText.overload("java.lang.CharSequence").implementation = function(x){ var string_to_send_x = x.toString(); var string_to_recv; // 把 js 的参数传入到 python send(str_to_send_x); recv(function(received_json_objection){ // 调用python的中的 .my_data方法 string_to_recv = received_json_objection.my_data console.log("string_to_recv", string_to_recv); }).wait(); var javaStringToSend = Java.use("java.lang.String").$new(string_to_recv); var result = this.setText(javaStringToSend); return result; } })python
import time import frida import base64 def my_message_handler(message, payload): print(message) print(payload) if message["type"] == "send": print(message["payload"]) data = message["payload"].split(":")[1].strip() print('message:', message) data = str(base64.b64decode(data)) print("data:", data) usr.pwd = data.split(":") print('pw: ',pw) data = str(base64.b64encode(("admin" + ":" + pw).encode())) print("encode data:", data) script.post({"my_data":data}) print("Modified data send ~") device = frida.get_usb_device() session = device.attach("com.example.lesson4sec") with open("lesson7sec.js") as f: script = session.create_script(f.read()) script.on("message", my_message_handler) script.load() input()
Frida 主动调用so
(function(){ Java.perform(()=>{ var so_addr = Module.findExportByName("libnative-lib.so", "symbol"); console.log("found address =>", so_addr); var use = new NativeFunction(so_addr, "pointer", ["pointer", "pointer", "pointer"]); var result = use(Java.vm.tryGetEnv(), Java.vm.tryGetEnv(), Java.vm.tryGetEnv().newStringUtf("12345roysue")); }) })()
Frida 加载 自制dex
使用 sdk 中的
d8工具 打包 编译好的 class 文件 具体路径 # Sdk > build-tools > 29.0.3 > d8使用 d8 编译目标文件
adb push /data/local/tmp
chmod 777 xxx.dex
Java.openClassFile("/data/local/tmp/xxx.dex").load(); const loadDex = Java.use("com.example.DexClass"); console.log("Frida load dex method test ",loadDex.test());
注意事项
若方法名和变量名相等,则修改变量名的值的时候需要在对象引用前加上
_若要修改的的变量是一个静态编写的时候,则需要使用
Java.useeg:Java.use("com.test.static_value").static_value.value = "change it ~";
&¥%……&……%……%¥……%……
frida 中的 int 表示 int.class
Integer.class.getField("TYPE").get(null);small objection
const Class = Java.use("java.lang.Class"); function inspectObject(obj){ const obj_class = Java.cast(obj.class, Class); const fields = obj_class.getDeclaredFields(); const methods = obj_class.getMethods(); console.log("Inspecting " + obj.getClass().toString()); console.log("\tFields:"); for(var i in fields) console.log("\t\t" + fileds[i].toString()); console.log("\tMethods:"); for(var i in methods) console.log("\t\t" + methods[i].toString()); }special write
function java_invoke(){ Java.perform(function(){ var cls2 = Java.use("com.lzy.dobbytest.test"); var String = Java.use("java.lang.String"); var Integer = Java.use("java.lang.Integer"); var type_int = Java.use("java.lang.Class").getPrimitiveClass("int"); // 拿到基本数据类型 // String 参数的方法 var method = cl22.class.getDeclaredMethod("showLog", Java.array("java.lang.Object", [String.class])); method.invoke(cls2.$new(), Java.array("java.lang.Object", ["test"])) // Int 参数的方法 var method = cls2.class.getDeclaredMethod("showLog", Java.array("java.lang.Object", [type_int])) console.log(method); // 这里的method是没有问题,下面的invoke 的参数有问题 method.invoke(cls2.$new, Java.array("java.lang.Object", [123])) method.invoke(cls2.$new, Java.array("java.lang.Object", [Integer.parseInt('123')])) // 同理 char/byte 也不行 }) }