【FridaHook整理】Frida安装及Hook安卓常用脚本

您所在的位置:网站首页 包包脚本 【FridaHook整理】Frida安装及Hook安卓常用脚本

【FridaHook整理】Frida安装及Hook安卓常用脚本

2023-09-21 16:37| 来源: 网络整理| 查看: 265

1 概述

在逆向过程中,Frida是非常常用的Hook工具,这个工具在日常使用的过程中,有很多通用方法又借鉴了部分网友的代码,我在这里整理记录一下,方便以后直接查阅及使用,部分函数使用的时候,可能需要稍微修改一下,本文记录是Android的方法,不涉及其他的,主要是搬迁的一下参考文章的片段: Frida官方文档 Android逆向之旅—Hook神器家族的Frida工具使用详解 看雪 Frida官方手册 - JavaScript API(篇一) 看雪 Frida官方手册 - JavaScript API(篇二) Js中几种String Byte转换方法

2 安装与启动方式 2.1 Frida安装

这个网上都已经有教程了,因为Frida大致原理是手机端安装一个server程序,然后把手机端的端口转到PC端,PC端写python脚本进行通信,而python脚本中需要hook的代码采用javascript语言。所以这么看来我们首先需要安装PC端的python环境,这个没难度直接安装python即可,然后开始安装frida了,直接运行命令:pip install frida 安装frida-tools:pip install frida-tools 在这里插入图片描述 要提前配置好python环境变量,不然提示pip命令找不到。安装完成后,再去官网下载对应版本的手机端程序frida-server:https://github.com/frida/frida/releases 注意: 这里一定要把frida-server版本和上面PC端安装的frida版本一致,不然运行报错的。其实这里看到真的实现hook功能的是手机端的frida-server,这个也是开源的大家可以研究他的原理。我们也看到这个工具和IDA是不是很类似,也是把手机端的端口转发到PC端进行通信而已。有了frida-server之后就好办了,直接push到手机目录下,然后修改一下文件的属性即可:

安装firda:pip install frida 安装frida-tools:pip install frida-tools 查找模拟器或者手机的CPU类型:adb shell getprop ro.product.cpu.abi frida server根据手机CPU型号下载合适的推送到手机 frida server 下载地址 我下载的是:frida-server-14.0.5-android-x86(需要解压缩成单文件之后推送手机) 连接手机或者mumu模拟器:adb connect 127.0.0.1:7555 (7555为mumu模拟器端口号,其它百度) 将文件push 进手机的指定目录下:adb push frida-server-14.0.5-android-x86 /data/local/tmp/ 进入手机端命令:adb shell 多个设备进入某一指定设备:adb -s emulator-5554 shell 切换获取手机的root权限:su 查找文件是否在手机中:cd /data/local/tmp/ 查看路径下的文件并看文件的权限:ls -l 拥有root权限更改文件的权限为777:chmod 777 frida-server-14.0.5-android-x86 在手机中启动运行该文件: ./frida-server-14.0.5-android-x86 & 电脑运行检查手机端服务是否开启成功: frida-ps -U windows运行 端口转发到PC:adb forward tcp:27043 tcp:27043

若文件推送错误,删除办法:

进入手机端命令:adb shell 切换获取手机的root权限:su 进入系统内指定文件夹:cd /data/local/tmp/ 列表显示当前文件夹内容 :ls 删除名字为xxx的文件夹及其里面的所有文件:rm -r xxx 删除文件指定文件xxx :rm xxx

按照上面的命令直接一步步执行就行,因为我之前已经push过,在这里就不在演示了,直接演示开启frida-server的命令,如果在检查的时候,发现没有开启,就去做一次端口的转发。 在这里插入图片描述 到这里frida 安装配置与手机互通的工作就做完了,接下来就开始在PC端开始编写hook程序进行操作了:

2.2 使用js脚本启动 frida -U -l exploit.js -f com.package.name

其中js脚本写法方式如下:

setImmediate(function() { console.log("[*] Starting script"); Java.perform(function() { myClass = Java.use("com.package.name.xxx某Activity"); myClass.implementation = function(v) { // do sth. } }) }) 2.3 使用python脚本启动 import frida, sys jscode = """ Java.perform(function () { //这里写要Hook的软件的类名,建议配合jadx和JEB使用 var Myclass= Java.use('这里填写要Hook的类名'); //这里写要Hook的类下的方法名Mymethod Myclass.Mymethod.implementation = function (str) { //这里是输出打印相关的提示语结果 send('Hook success'); console.log('string is: ' + str)); }; }); """ def on_message(message, data): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message) //这里写要Hook的软件的包名 process = frida.get_usb_device().attach('这里写软件的包名') #pid = device.spawn(["com.android.chrome"]) #session = device.attach(pid) #device.resume(pid) script = process.create_script(jscode) script.on('message', on_message) print('[*] Hook Start Running') script.load() sys.stdin.read() 3 Android 常用Hook方法汇总 Hook 一般函数—使用implementation Hook一般函数使用案例1: var MainActivity = Java.use('ese.xposedtest.MainActivity'); //外部类 修改返回值 MainActivity.OutClass.implementation = function (arg) { var ret = this.OutClass(arg); console.log('Done:' + arg); return ret; } Hook一般函数使用案例2: import frida, sys # Hook软件的类名下的方法实现Hook 传入需要的参数 看方法是否有返回值 bscode = """ Java.perform( function () { //获取当前安卓设备的系统版本 var v=Java.androidVersion; send('Version:'+v); //打印调用堆栈 function printstack() { send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())); } //Hook软件包的类名为:com.myclass var myclass= Java.use('com.myclass'); //调用Hook软件包类名下的方法:mymethod myclass.mymethod.implementation = function (bytearray) { send('com.myclass.mymethod.implementation'); printstack(); var ret = this.mymethod(bytearray); send("result:"+ret); return ret; } } ); """ def on_message(message, data): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message) process = frida.get_usb_device().attach('这里是包名') #Hook软件的包名 script = process.create_script(bscode) script.on('message', on_message) print('[*] Running CTF') script.load() sys.stdin.read() Hook 重载函数—使用overload //如果一个类的两个方法具有相同的名称,您需要使用"重载",若不知具体参数,出错会有提示的。 myClass.myMethod.overload().implementation = function(){ // do sth } myClass.myMethod.overload("[B", "[B").implementation = function(param1, param2) { // do sth } myClass.myMethod.overload("android.context.Context", "boolean").implementation = function(param1, param2){ // do sth } 拦截方法的所有方法重载代码示例1: function hook_overload_8() { if(Java.available) { Java.perform(function () { console.log("start hook"); var targetMethod = 'add'; var targetClass = 'com.roysue.roysueapplication.Ordinary_Class'; var targetClassMethod = targetClass + '.' + targetMethod; //目标类 var hook = Java.use(targetClass); //重载次数 var overloadCount = hook[targetMethod].overloads.length; //打印日志:追踪的方法有多少个重载 console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]"); //每个重载都进入一次 for (var i = 0; i console.warn("n*** entered " + targetClassMethod); //可以打印每个重载的调用栈,对调试有巨大的帮助,当然,信息也很多,尽量不要打印,除非分析陷入僵局 Java.perform(function() { var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()); console.log("nBacktrace:n" + bt); }); // 打印参数 if (arguments.length) console.log(); for (var j = 0; j var partial = ""; var result = this.$init(arg); if (arg !== null) { partial = arg.toString().replace('\n', '').slice(0,10); } // console.log('new StringBuilder(java.lang.String); => ' + result) console.log('new StringBuilder("' + partial + '");') return result; } console.log('[+] new StringBuilder(java.lang.String) hooked'); Hook 生成对象—使用$new const JavaString = Java.use('java.lang.String'); var exampleString1 = JavaString.$new('Hello World, this is an example string in Java.'); console.log('[+] exampleString1: ' + exampleString1); Hook 内部类—使用$ 案例1:拦截内部类参数代码示例1 var inInnerClass = Java.use('ese.xposedtest.MainActivity$inInnerClass'); inInnerClass.methodInclass.implementation = function(){ var arg0 = arguments[0]; var arg1 = arguments[1]; send("params1: "+ arg0 +" params2: " + arg1); return this.formInclass(1,"Frida"); } 案例2:拦截内部类函数代码示例2 function hook_overload_3() { if(Java.available) { Java.perform(function () { console.log("start hook"); //注意此处类的路径填写更改所分析的路径 var clz = Java.use('com.roysue.roysueapplication.User$clz'); if(clz != undefined) { //这边也是像正常的函数来hook即可 clz.toString.implementation = function (){ console.log("成功hook clz类"); return this.toString(); } } else { console.log("clz: undefined"); } console.log("start end"); }); } } Hook 枚举所有的类及方法 枚举所有的类并定位类代码示例: setTimeout(function (){ Java.perform(function (){ console.log("n[*] enumerating classes..."); //Java对象的API enumerateLoadedClasses Java.enumerateLoadedClasses({ //该回调函数中的_className参数就是类的名称,每次回调时都会返回一个类的名称 onMatch: function(_className){ //在这里将其输出 console.log("[*] found instance of '"+_className+"'"); //如果只需要打印出com.roysue包下所有类把这段注释即可,想打印其他的替换掉indexOf中参数即可定位到~ //if(_className.toString().indexOf("com.roysue")!=-1) //{ // console.log("[*] found instance of '"+_className+"'"); //} }, onComplete: function(){ //会在枚举类结束之后回调一次此函数 console.log("[*] class enuemration complete"); } }); }); }); 枚举类的所有方法并定位方法代码示例: function enumMethods(targetClass) { var hook = Java.use(targetClass); var ownMethods = hook.class.getDeclaredMethods(); hook.$dispose; return ownMethods; } function hook_overload_5() { if(Java.available) { Java.perform(function () { var a = enumMethods("com.roysue.roysueapplication.User$clz") a.forEach(function(s) { console.log(s); }); }); } } Hook 拦截类的所有方法 拦截类的所有方法代码示例: function traceClass(targetClass) { //Java.use是新建一个对象哈,大家还记得么? var hook = Java.use(targetClass); //利用反射的方式,拿到当前类的所有方法 var methods = hook.class.getDeclaredMethods(); //建完对象之后记得将对象释放掉哈 hook.$dispose; //将方法名保存到数组中 var parsedMethods = []; methods.forEach(function(method) { //通过getName()方法获取函数名称 parsedMethods.push(method.getName()); }); //去掉一些重复的值 var targets = uniqBy(parsedMethods, JSON.stringify); //对数组中所有的方法进行hook targets.forEach(function(targetMethod) { traceMethod(targetClass + "." + targetMethod); }); } function hook_overload_9() { if(Java.available) { Java.perform(function () { console.log("start hook"); traceClass("com.roysue.roysueapplication.Ordinary_Class"); console.log("hook end"); }); } } s1etImmediate(hook_overload_9); Hook 拦截Java层类的所有子类 //枚举所有已经加载的类 Java.enumerateLoadedClasses({ onMatch: function(aClass) { //迭代和判断 if (aClass.match(pattern)) { //做一些更多的判断,适配更多的pattern var className = aClass.match(/[L]?(.*);?/)[1].replace(///g, "."); //进入到traceClass里去 traceClass(className); } }, onComplete: function() {} }); Hook native 函数 Interceptor.attach(Module.findExportByName("xxx.so" , "xxxx"), { onEnter: function(args) { send("open(" + Memory.readCString(args[0])+","+args[1]+")"); }, onLeave:function(retval){ } }); Hook 静态变量(属性)/参考文章中有反射的方法 var ah = Java.use("com.ah"); console.log("To Log: " + ah.a.value); ah.a.value = true; Hook 获取设备版本及打印堆栈 // 获取当前安卓设备的系统版本 var v = Java.androidVersion; send('Version:' + v); // 打印调用堆栈 function printstack() { send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())); } RPC远程调用Java层函数(获上下文) rpc导出Java层函数代码示例1: import codecs import frida from time import sleep # 附加进程名称为:com.roysue.roysueapplication session = frida.get_remote_device().attach('com.roysue.roysueapplication') # 这是需要执行的js脚本,rpc需要在js中定义 source = """ //定义RPC rpc.exports = { //这里定义了一个给外部调用的方法:sms sms: function () { var result = ""; //嵌入HOOK代码 Java.perform(function () { //拿到class类 var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class"); //最终rpc的sms方法会返回add(1,3)的结果! result = Ordinary_Class.add(1,3); }); return result; }, }; """ # 创建js脚本 script = session.create_script(source) script.load() # 这里可以直接调用java中的函数 rpc = script.exports # 在这里也就是python下直接通过rpc调用sms()方法 print(rpc.sms()) sleep(1) session.detach() rpc导出Java层函数 酷安代码示例2: import frida, sys, codecs, os # def adbforward(): # os.system('adb forward tcp:27042 tcp:27042') # os.system('adb forward tcp:27043 tcp:27043') # 酷安10.5.3版本 Frida_hook_rpc jscode = """ rpc.exports = { //gethello 是自己定义的函数名,str是参数,根据实际传参,不要大写。 gethello: function(str){ send('hello'); var sig = '' Java.perform(function(){ //拿到软件里的context上下文信息 这是一个生命周期之后启动的类,启动后就可看到里面有上下文信息 var currentApplication = Java.use('android.app.ActivityThread').currentApplication(); var context = currentApplication.getApplicationContext(); //软件的类名 var AuthUtils = Java.use('com.coolapk.market.util.AuthUtils'); //类下面的方法,传入的参数信息string类型 可以模拟传入 sig = AuthUtils.getAS(context, str); send(sig); }); return sig; } } """ def on_message(message, data): if message['type'] == 'send': print("[*] {0}".format(message['payload'])) else: print(message) # Hook的软件包名 process = frida.get_usb_device().attach('com.coolapk.market') script = process.create_script(jscode) script.on('message', on_message) print('[*] Running CTF') script.load() # 回调执行函数,传入模拟字段参数的信息 script.exports.gethello('fd017bd5ed4e942da40e5673') # sys.stdin.read() byte转String function byte2string(array){ var result = ""; for(var i = 0; i var bytes = []; for (var i = 0; i var arr = []; for (var i = 0, j = str.length; i console.log(fileData) var dataString = ""; for (var i = 0; i return new Uint16Array(buf) // encodedString = String.fromCodePoint.apply(null, new Uint16Array(buf)); // // decodedString = encodeURI(encodedString);//没有这一步中文会乱码 // // console.log(decodedString); // return encodedString } string转ArrayBuffer(模板) function str2ab(str) { var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节 var bufView = new Uint16Array(buf); for (var i = 0, strLen = str.length; i if (!uint8arr) { return ''; } var hexStr = ''; for (var i = 0; i if (!uint8arr) { return ''; } var hexStr = ''; for (var i = 0; i if (!str) { return new Uint8Array(); } var a = []; for (var i = 0, len = str.length; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3