下载安装和简要说明
下载:
1 | pip install frida-tools |
下载 github 上的 frida server,类似ida的server;
Releases · frida/frida (github.com)
需要下载的名称为:frida-server-16.0.10-android-arm64.xz;(模拟器下载x64版本)
之后熟悉adb的使用:(需要root手机,模拟器也行但比较麻烦)
adb下载安装及使用_Dongs丶的博客-CSDN博客_adb下载
需要用到的指令:
1 | adb devices //查看是否连接到手机设备 |
使用命令以激活server:
1 | ./frida_server64 |
查看APP包名:
1 | adb shell pm list packages -3 |
MuMu模拟器特殊说法:
1 | adb connect 127.0.0.1:7555 //以usb连接到模拟器 |
指定设备转发端口:
1 | adb -s ID forward tcp:xxx tcp:xxx |
frida常用参数
执行命令: frida-ps, 展示进程应用;
1 | -f //启动app |
如加载一个app并装载脚本:
1 | frida -R -f app包名 -l 脚本.js |
Frida实现调用函数
用Jeb找到包名,类名,以及函数名及其调用约定;
编写JS执行:
1 | Java.perform(function() |
总结:
1 | //开头 |
Frida简单实现hook-java层
不管是否静态,可以如下书写:
1 | ClassName.FuncName.implementation = function(p1,p2,...) |
也是需要和上面的一样,先构造类常量,然后实例化;
此写法是直接覆盖原函数的内容,不会执行原本函数的内容,所以要规定好调用约定,返回对应的内容;
在改写函数中使用:
1 | this.FuncName(...) |
可以实现调用此类的原函数;
如果函数有重载,则写法如下:
1 | ClassName.FuncName.overload('').implementation = function(p1,p2,...) |
单引号里是参数的类型,如果是基本类型,则表示法为: [B
表示为byte;
如果是类类型,则直接输入其对应包的对应类名就行,如String类型: java.lang.String
;
一般而言,对于java常用类的函数hook,要有过滤,即对应地方调用的参数特点做出if判断并更改代码逻辑;
因为很多地方也会调用到相同的函数,此时就直接返回 this.FuncName() ,就不会使得程序崩溃;
Hook so层
hook so层要注意一点,要当so文件动态链接到应用后,才能调用其函数,不然会空指针报错,这和pwn的ret2libc一个道理;
hook so一般有两种方法,这里先介绍第一种,导出表 Export,找到导出的地址;
操作so层时不用 java.use ,用拦截器: Interceptor;
这里用获取一个函数传参结构体的打印代码解释:
假设原代码:
1 | a = AimFunc(a1,a2,&v16,...); |
此时第三个参数便是此时需要获取的结构体地址;
在32位程序中,指针占4字节,而结构体的地址过去第一个字段是真实的结构体数据的指针,隔了4个字节之后的,是这个结构体的大小;
那么对应hook代码如下:
1 | //此函数接收一个指针,一般指向hook函数 |
此时直接跑是会报错的,因为正如前面所述,在程序开始运行的时候就直接去寻找模块了,但是因为so还没有动态地链接,所以找不到,会得到一个null指针;
此时的解决思路是:找到加载此so文件的函数,先去hook掉java层的 LoadLibrary,再对比此时传入 LoadLibrary 参数是否是目标so文件,如果是,则再实现上面的代码,如果不是,则实现原函数代码内容;
通过java层的源码分析可以知道:LoadLibrary 的实现是 调用了一个 LoadLibrary0(a1,a2,a3)去实现主要代码的,而主要代码的逻辑是:如果传入的字符串是存在的so文件,那么就会直接在其中调用 nativeLoad 函数;
而 nativeload 函数也会层层调用,最后会找到一个三参的 nativeload,原型如下:
1 | private static native String nativeLoad(String filename, ClassLoader loader, Class<?> caller); |
此时需要hook的函数,也就是这上面这个了;
主要代码如下:
1 | //因为hook java层,所以用java.use,上述目标函数在runtime里 |
如果想要将想要的data数据dump出,可以用以下代码(frida提供):
1 | //路径 + 大小 + 后缀名 (总名称) |
完整代码如下:
1 | Java.perform(function(){ |
第二种找到so内目标函数的方法是,没有export的情况,需要用偏移量来进行寻址,在attach函数调用的那一步,改写为:
1 | const so = Process.findModuleByName('your_so.so') |
在IDA逆so的时候,设置segement为0,可以定位函数的地址直接为偏移量;
arm汇编中,函数传参使用r0~r4;