Frida基础

server/2024/9/25 19:16:07/

Frida介绍

        官 网 对 Frida 的 介 绍 是 “Frida 是 平 台 原 生 App 的 Greasemonkey” ,专业一点就是一种动态插桩工具,可以插入一些 代码到原生App的内存空间去动态地监视和修改其行为,这些原生平 台可以是Windows、Mac、Linux、Android或者iOS,同时Frida还 是开源的。 Greasemonkey可能看起来十分陌生,其实它是Firefox的一套 插件体系,通过利用Greasemonkey插入自定义的JavaScript脚本可 以定制网页的显示或行为方式;换而言之,可以直接改变Firefox对网 页的编排方式,从而实现想要的任何功能。同时这套插件还是“外 挂”的,非常灵活机动。同样,Frida也可以通过将JavaScript脚本 插入到App的内存中来对App的逻辑进行跟踪和监控,甚至重新修改 程序的逻辑,实现逆向开发和分析人员想要实现的功能,这样的方式 也可以称为Hook(钩住,即通过钩子机制与钩子函数建立关联)。

        Frida目前非常火爆,该框架从Java层Hook到Native层Hook无 所不能,虽然持久化还是要依靠Xposed和HookZz等开发框架,但是Frida的动态特性和灵活性对逆向过程以及自动化逆向过程的帮助非 常巨大。

Frida为什么这么火爆呢?

        在逆向工作中,使用Frida可以“看到”平时看不到的东西。出 于编译型语言的特性,机器码在CPU和内存上执行时,其内部数据的 交互和跳转对用户来讲是看不见的。当然,如果手上有源码,哪怕有 带调试符号的可执行文件包,也可以使用gdb、lldb等调试器连上去 进行调试和查看。 如果没有呢?比如纯黑盒,此种情况下,如果仍旧要对App进行 逆向过程和动态调试,甚至进行自动化的分析和规模化的信息收集, 那么我们就需要一种可编程的框架,它具有细粒度的流程控制、代码 级的可定制体系以及不断对调试进行动态纠正,Frida就是这种框 架。 Frida使用的是Python、JavaScript等“胶水语言” ,这可能也 是它火爆的一个原因,Frida可以迅速地将逆向过程自动化,并整合 到现有的架构和体系中去,为发布“威胁情报”“数据平台”“AI风 控”等产品打好基础。

其中Frida环境搭建我会另写一篇文章说明。

Frida基础介绍

        在Android逆向过程中,Frida存在两种操作模式:一种是通过命令行直接将JavaScript脚本注入进程中,对进程进行操作,称为CLI(命令行)模式;另一种是使用Python进行JavaScript脚本的注 入工作,实际对进程进行操作的还是JavaScript脚本,这种操作模式 称为RPC模式。两种模式本质上是一样的,最终执行Hook工作的都 是JavaScript脚本,而且核心执行注入工作的还是Frida本身,只是RPC模式在对复杂数据的处理上可以通过RPC传输给Python脚本来 进行,这样有利于减少被注入进程的性能损耗,在大规模调用中更加 普遍。在本章中,笔者主要使用CLI模式进行操作。 Frida操作App的方式有两种。第一种是spwan模式,简而言之 就是将启动App的权利交由Frida来控制。采用这个模式时,即使目标 App已经启动,在使用Frida注入程序时还是会重新启动App。在CLI 模式中,Frida通过加上-f参数指定包名以spwan模式操作App。第二 种attach模式,建立在目标App已经启动的情况下,Frida通过 ptrace注入程序从而执行Hook的操作。在CLI模式中,如果不添加-f 参数,则默认会通过attach模式注入App。

学习使用API

1.静态方法和实例方法的hook

var money = Java.use("com.xiaojianbang.hook.Money");//目标包中的类或者方法名money.getInfo.implementation = function(){var result = this.getInfo();console.log("money.getInfo result:",result);return result;}//hook静态方法money.setFlag.implementation = function(a){console.log("money.setFlage param:",a);return this.setFlag(a);}// 引入 Java 类 com.xiaojianbang.hook.Money,
var money = Java.use("com.xiaojianbang.hook.Money");// 拦截 getInfo 方法的实现
money.getInfo.implementation = function(){// 调用原始的 getInfo 方法var result = this.getInfo();// 记录获取的结果console.log("money.getInfo result:",result);// 返回原始结果return result;
}// 拦截静态方法 setFlag 的实现
money.setFlag.implementation = function(a){// 记录传入的参数console.log("money.setFlage param:",a);// 调用原始的 setFlag 方法并返回结果return this.setFlag(a);
}功能:
拦截了 com.xiaojianbang.hook.Money 类的 getInfo 方法和 setFlag 静态方法,
并在调用时记录信息。

2.函数参数和返回值的修改

// 定义变量money,使用Java.use方法获取com.xxx.hook.Money类
var money = Java.use("com.xxx.hook.Money");// 定义变量str,使用Java.use方法获取java.lang.String类
var str = Java.use("java.lang.String");// 重写money对象的getInfo方法
money.getInfo.implementation = function(){// 调用原始的getInfo方法,并将结果保存到result变量中var result = this.getInfo();// 打印结果到控制台console.log("money.getInfo result:",result);// 返回一个新的字符串对象return str.$new("xxxx");
};// 重写money对象的setFlag方法
money.setFlag.implementation = function(a){// 打印传入的参数到控制台console.log("money.setFlag param:",a);// 调用原始的setFlag方法,并返回一个新的字符串对象return this.setFlag("xxxxx");
};其中:
return str.$new("xxxx");`str`: 是之前通过`Java.use()`方法获取的`java.lang.String`类的引用。`$new("xxxx")`: 这是Frida库的一种特殊用法,用于在Java堆上创建一个新的实例。
在这里,`"xxxx"`是作为参数传递给`String`类的构造函数的,它将创建一个包含指定字符串的
新的`String`对象。作用是创建一个新的Java字符串对象,其内容为"xxxx",然后将该字符串对象作为返回值
返回给调用者。使用Frida库对Java代码进行动态Hook。通过重写Money类的getInfo和setFlag方法,
可以在调用这些方法时打印出相应的日志,并返回自定义的结果。

3.构造方法的hook $init

// 引入 Java 类 com.xxx.hook.Money
var money = Java.use("com.xxx.hook.Money");// 拦截 $init 构造函数的实现
money.$init.implementation = function(a, b){// 记录传入的参数console.log("money.$init param:", a, b);// 返回修改后的构造函数结果,这里可能会导致问题,因为可能无法直接调用构造函数的重载形式return this.$init("美元", 200);
}拦截了 com.xxx.hook.Money 类的构造函数 $init,并在调用时记录信息并修改构造函数的参数。
不过需要注意的是,直接调用构造函数的重载形式可能会导致问题,因为通常情况下我们无法直接调用构造函数的不同形式。

4.对象参数的构造与修改

// 引入 Java 类 com.xxx.hook.Wallet
var wallet = Java.use("com.xxx.hook.Wallet");// 引入 Java 类 com.xxx.hook.Money
var money = Java.use("com.xxx.hook.Money");// 拦截 deposit 方法的实现
wallet.deposit.implementation = function(a){// 输出参数 a 的信息,假设 a 是 Money 类型的对象console.log("wallet.deposit param:", a.getInfo());// 使用 money.$new() 创建一个新的 Money 对象,并传入参数 "美元" 和 200var newMoney = money.$new("美元", 200);// 调用原始的 deposit 方法并返回结果,使用新创建的 Money 对象作为参数return this.deposit(newMoney);
}// 引入 Java 类 com.xxx.hook.Wallet
var wallet = Java.use("com.xxx.hook.Wallet");// 引入 Java 类 com.xxx.hook.Money
var money = Java.use("com.xxx.hook.Money");// 拦截 deposit 方法的实现
wallet.deposit.implementation = function(a){// 设置参数 a 的金额为 2000,假设 a 是 Money 类型的对象a.setAmount(2000);// 输出参数 a 的信息,假设 a 是 Money 类型的对象console.log("wallet.deposit param:", a.getInfo());// 调用原始的 deposit 方法并返回结果return this.deposit(a);
}拦截了 com.xxx.hook.Wallet 类的 deposit 方法,并在调用时将参数 a 的金额
设置为 2000,然后记录参数 a 的信息,最后调用原始的 deposit 方法并返回结果。

5.HashMap的打印

// 导入需要的 Java 类
var utils = Java.use("com.xxx.hook.Utils");var stringBuilder = Java.use("java.lang.StringBuilder");// 重写 utils.shufferMap 方法
utils.shufferMap.implementation = function(a){// 获取参数 a 的键集合var key = a.keySet();// 获取键的迭代器var it = key.iterator();// 创建一个 StringBuilder 对象用于存储结果var result = stringBuilder.$new();// 遍历键集合while(it.hasNext()){// 获取键var keystr = it.next();// 根据键获取值var valuestr = a.get(keystr);// 将值添加到 StringBuilder 中result.append(valuestr);}// 打印拼接后的字符串console.log("utils.shfferMap 参数:",result.toString());// 调用原始的 shufferMap 方法,并获取结果var result = this.shufferMap(a);// 打印原始方法的返回结果console.log("utils.shufferMap 结果:",result);// 返回结果return result;
}进行 Java 层面的 Hook,具体来说是针对 com.xxx.hook.Utils 类中的 shufferMap 方法。
代码解释:
在方法的实现中,先获取参数中键值对的键集合,然后遍历这个键集合,将对应的值逐个拼接到一个 
StringBuilder 对象中,最后打印拼接后的字符串,并调用原始的 shufferMap 方法,最终返回结果。

6.重载方法的hook

// 导入需要的 Java 类
var utils = Java.use("com.xxx.hook.Utils");// 重写接受两个整型参数的 getCalc 方法
utils.getCalc.overload('int','int').implementation = function(a,b){// 打印传入的两个整型参数console.log("utils.getCalc 参数:", a, b);// 调用原始的 getCalc 方法并返回结果return this.getCalc(a,b);
}// 重写接受四个整型参数的 getCalc 方法
utils.getCalc.overload('int','int','int','int').implementation = function(a,b,c,d){// 打印传入的四个整型参数console.log("utils.getCalc 参数:", a, b, c, d);// 调用原始的 getCalc 方法并返回结果return this.getCalc(a,b,c,d);
}对 com.xxx.hook.Utils 类中的两个重载方法 getCalc 进行 Hook。第一个重载方法接受两个整型参数,第二个重载方法接受四个整型参数。在 Hook 的实现中,打印出传入的参数,并调用原始的方法,最终返回其结果

7.主动调用

// 引入Java类 com.xxx.hook.Money,并赋值给变量 money
var money = Java.use("com.xxx.hook.Money");// 调用 money 对象的 setFlag 方法,设置标志为 "xiaojianbang"
money.setFlag("xiaojianbang");// 创建一个名为 moneyObj 的新的 Money 对象,参数为 "卢布" 和 1100
var moneyObj = money.$new("卢布", 1100);// 打印 moneyObj 对象的 getInfo 方法
console.log(moneyObj.getInfo);// 在内存中选择所有类型为 com.xxx.hook.Money 的对象
Java.choose("com.xxx.hook.Money", {// 当找到对象时执行的回调函数onMatch: function(obj) {// 打印对象的 getInfo 方法返回的信息console.log(obj.getInfo());},// 完成搜索后执行的回调函数onComplete: function() {console.log("内存中的 Money 对象搜索完毕");}
});
使用 Frida 进行 Android 应用程序的 Hook。通过 Java.use() 方法引入com.xxx.hook.Money 类,
然后调用其中的方法和属性。其中,money.setFlag("xiaojianbang") 设置了一个标志。接着,创建了一个新的 Money 对象 moneyObj,并传入了参数 "卢布" 和 1100。然后,通过 console.log() 打印了 moneyObj 对象的 getInfo 方法。最后,通过 Java.choose() 方法在内存中选择了所有类型为 com.xxx.hook.Money 的对象,并对每个对象执行了一些操作。

8.android Context的获取

// 使用 Java.use() 方法引入 android.app.ActivityThread 类,并获取当前应用程序
var current_application = Java.use('android.app.ActivityThread').currentApplication();// 获取当前应用程序的应用上下文
var context = current_application.getApplicationContext();

使用 Frida 来获取 Android 应用程序的应用上下文。

首先,使用 Java.use() 方法引入 android.app.ActivityThread 类,然后调用 currentApplication() 方法获取当前的应用程序对象。
然后,通过调用 getApplicationContext() 方法获取应用程序的上下文对象,并将其赋值给变量 context。


http://www.ppmy.cn/server/25211.html

相关文章

SSRF漏洞是什么,如何进行有效防护

SSRF全称:Server-Side Request Forgery,即,服务器端请求伪造。是一个由攻击者构造请求,在目标服务端执行的一个安全漏洞。攻击者可以利用该漏洞使服务器端向攻击者构造的任意域发出请求,目标通常是从外网无法访问的内部…

Python爬虫:BeautifulSoup

安装 打开cmd,键入pip install bs4,下载慢的用清华源 BeautifulSoup 一,概念 bs4数据解析的一种工具,其实和正则表达式差不多的用处,但是bs返回的是网页源代码,我们通过bs4返回的对象可以直接操作标签的标签的各种属性达到加快筛…

【ARMv9 DSU-120 系列 9 -- DSU-120 Debug block】

请阅读【Arm DynamIQ™ Shared Unit-120 专栏 】 请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 文章目录 ARM DSU-120 Debug BlockCluster debug componentsCache DebugDSU-120 Cache Debug 特性应用场景Terminology处理元素(PE)

【Vue3进阶】- Router 4

Vue Router 是 Vue.js 官方提供的路由管理器,它与 Vue.js 核心深度集成,使得构建单页面应用(SPA)变得容易。在单页面应用中,所有视图和组件都通过路由来管理和切换,而不是传统的整页刷新。 在本课文中将介…

C基础语法速览

叠甲:以下文章主要是依靠我的实际编码学习中总结出来的经验之谈,求逻辑自洽,不能百分百保证正确,有错误、未定义、不合适的内容请尽情指出! 文章目录 1.数据类型1.1.数据类型的常见分类1.2.数据类型的符号修饰1.3.数据…

CSS的布局模式

前言&#xff1a; 我们可以看到京东的官网上的一些例子&#xff08;如下图&#xff09;&#xff0c;在同一排中能够存在多个div&#xff0c;这是通过布局方式&#xff08;例如浮动&#xff09;来实现的。 CSS传统的布局模式&#xff1a; <1>普通流&#xff08;又称之为标…

多家企业机密数据遭Lockbit3.0窃取,亚信安全发布《勒索家族和勒索事件监控报告》

本周态势快速感知 本周全球共监测到勒索事件87起&#xff0c;与上周相比勒索事件大幅下降。美国依旧为受勒索攻击最严重的国家&#xff0c;占比45%。 本周Cactus是影响最严重的勒索家族&#xff0c;Lockbit3.0和Bianlian恶意家族紧随其后&#xff0c;从整体上看Lockbit3.0依旧…

ASP.NET教务管理平台-权限及公共模块设计与开发

摘 要 随着教育改革的不断深化&#xff0c;高等院校的建设与发展对国民整体素质的提高起着越来越重要的作用&#xff0c;建立一套能够适应这些改变的行政管理方案也就显得尤为重要。对于教务处来说&#xff0c;将信息技术用于校务管理中便是迫切的要求。 教务系统中的用户…