Frida入门总结
2020-03-15 13:00:00 Author: mp.weixin.qq.com(查看原文) 阅读量:115 收藏

本文为看雪论坛优秀文章
看雪论坛作者ID:windy_ll

一、Frida概述
Frida是一款轻量级HOOK框架,可用于多平台上,例如Android、Aindows、iOS等。

frida分为两部分,服务端运行在目标机上,通过注入进程的方式来实现劫持应用函数,另一部分运行在系统机器上。

frida上层接口支持js、python、c等。

Frida官方github地址为:frida官方github地址
(https://github.com/frida)
二、Frida安装
1. 安装python3.7并配置好环境变量(官方推荐python3以上版本至少为3.7),python安装包官方下载地址:https://www.python.org/downloads/。
 
2. 安装frida模块,命令为pip install frida(配置了多个python版本环境的可以使用命令python -m pip install frida防止用pip install frida命令报错)。
 
 
3. 安装frida-tools模块,命令同上,pip install frida-tools或者python -m pip install frida-tools。
 
 
4. 下载运行在目标机上的frida-sever端,官方下载地址:https://github.com/frida/frida/releases,下载时要选择对应的版本下载,例如我的机器为arm32为架构,就选择frida-server-12.8.14-android-arm.xz下载。(可以在adb使用命令cat /proc/cpuinfo查询)
 
 
 
5. 将第四步下载好的文件解压,然后通过命令adb push 你的电脑是存放位置 /data/local/tmp将文件传输到手机中,然后通过adb shell进入手机端,给文件赋权777,并于root权限启动。
 
 
 
6. 做完以上几步后,新开一个命令行输入命令frida-ps -U查看手机进程,如果出现以下结果,则frida安装成功。
 
三、Frida Hook Java层
1. 编写一个小demo用来hook,该demo关键部分代码如下:
 
2. 现在我们将该apk安装好,运行看一下未Hook前的显示字符串。
 
 
3. 现在来编写Hook的Python脚本,脚本代码如下:
import frida  #导入frida模块import sys    #导入sys模块 jscode = """  #从此处开始定义用来Hook的javascript代码    Java.perform(function(){         var MainActivity = Java.use('com.example.testfrida.MainActivity'); //获得MainActivity类        MainActivity.testFrida.implementation = function(){ //Hook testFrida函数,用js自己实现            send('Statr! Hook!'); //发送信息,用于回调python中的函数            return 'Change String!' //劫持返回值,修改为我们想要返回的字符串        }    });""" def on_message(message,data): #js中执行send函数后要回调的函数    print(message) process = frida.get_remote_device().attach('com.example.testfrida') #得到设备并劫持进程com.example.testfrida(该开始用get_usb_device函数用来获取设备,但是一直报错找不到设备,改用get_remote_device函数即可解决这个问题)script = process.create_script(jscode) #创建js脚本script.on('message',on_message) #加载回调函数,也就是js中执行send函数规定要执行的python函数script.load() #加载脚本sys.stdin.read()

4. 现在python脚本编写完毕,我们来执行该脚本,首先手机端执行frida,然后通过命令adb forward tcp:27043 tcp:27043和adb forward tcp:27042 tcp:27042来转发这两个端口,接着在手机上运行该应用程序,在命令行中执行脚本,最后点击应用的按钮,即可看到字符串已经被替换成我们要替换的了。
 
 
 
 
四、Frida Hook Native层

Hook native层返回值为int类型的demo

1. 还是先写一个小demo,下面贴一下关键代码(很简单c语言代码就不再解释了,至于native层函数怎么编写,由于本篇主要不是讲怎么编写so函数,就不过多叙述了,实在不会的可以看一下我的一篇博客,我觉得写得还是挺详细的,博客编写native层函数链接:https://www.cnblogs.com/aWxvdmVseXc0/p/11564809.html)和未Hook前截图:
 
 
代码:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_fridaso_FridaSoDefine */ #ifndef _Included_com_example_fridaso_FridaSoDefine#define _Included_com_example_fridaso_FridaSoDefine#ifdef __cplusplusextern "C" {#endif/** Class:     com_example_fridaso_FridaSoDefine* Method:    FridaSo* Signature: (II)I*/JNIEXPORT jint JNICALL Java_com_example_fridaso_FridaSoDefine_FridaSo(JNIEnv *env, jclass obj, jint a, jint b){    int c;    c = a + b;    return c;} #ifdef __cplusplus}#endif#endif 

 
2. 接下来我们来写python hook脚本,我们需要hook native层这个函数,达到返回值修改为0的效果。
写到这里需要说明一下关于so文件当中的函数,分为导出函数和未导出函数两种,导出函数打开IDA后能够在导出表中找到的函数就是导出函数,未导出函数则在导出表中寻找不到,一般来说静态编写的native函数都能在导出表中寻找到,而动态加载的则无法在导出表中发现!
 
 
代码如下:(跟上面hook java层重复的代码不在注释详讲了。)
import fridaimport sys jscode = """Java.perform(function(){    //下面这一句代码是指定要Hook的so文件名和要Hook的函数名,函数名就是上面IDA导出表中显示的那个函数名    Interceptor.attach(Module.findExportByName("libfridaso.so","Java_com_example_fridaso_FridaSoDefine_FridaSo"),{        //onEnter: function(args)顾名思义就是进入该函数前要执行的代码,其中args是传入的参数,一般so层函数第一个参数都是JniEnv,第二个参数是jclass,从第三个参数开始才是我们java层传入的参数        onEnter: function(args) {            send("Hook start");            send("args[2]=" + args[2]); //打印我们java层第一个传入的参数            send("args[3]=" + args[3]); //打印我们java层传入的第二个参数        },        onLeave: function(retval){ //onLeave: function(retval)是该函数执行结束要执行的代码,其中retval参数即是返回值            send("return:"+retval); //打印返回值            retval.replace(0); //替换返回值为0        }    });});"""def printMessage(message,data):    if message['type'] == 'send':        print('[*] {0}'.format(message['payload']))    else:        print(message) process = frida.get_remote_device().attach('com.example.fridaso')script = process.create_script(jscode)script.on('message',printMessage)script.load()sys.stdin.read()

3. 最后在手机端执行frida-server,转发端口,开启应用,执行脚本,点击按钮,即可看到返回值已经被修改成了0,效果图如下:
 
 
Hook native层返回值为String类型的demo
1. 上面已经写了怎么Hook修改native层函数返回值为int类型的情况,使用replace()函数直接修改即可,但是返回情况为字符串则不一样,在c语言中,返回值为字符串其实是返回了一个char *(字符串指针),所以简单的替换是无法取效果的,具体怎么修改返回值,接着看下面,下面还是贴上demo的关键代码和未Hook前截图:
 
 
代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_fridasostring_fridaSoString */ /* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_fridasostring_fridaSoString */ #ifndef _Included_com_example_fridasostring_fridaSoString#define _Included_com_example_fridasostring_fridaSoString#ifdef __cplusplusextern "C" {#endif/** Class:     com_example_fridasostring_fridaSoString* Method:    FridaSo* Signature: (Ljava/lang/String;)Ljava/lang/String;*/JNIEXPORT jstring JNICALL Java_com_example_fridasostring_fridaSoString_FridaSo(JNIEnv *env, jclass obj, jstring str){    return str;} #ifdef __cplusplus}#endif#endif

未Hook前运行截图:
 
 
2. 接下来是python Hook脚本(只解释与上面有差异的代码),Hook的函数具体函数名还是使用IDA去寻找。
 
 
python代码:
import fridaimport sys jscode = """Java.perform(function(){    Interceptor.attach(Module.findExportByName("libfridaso.so","Java_com_example_fridasostring_fridaSoString_FridaSo"),{        onEnter: function(args) {            send("Hook start");            send("args[2]=" + args[2]);        },        onLeave: function(retval){            send("return:"+retval);            var env = Java.vm.getEnv(); //获取env对象,也就是native函数的第一个参数            var jstrings = env.newStringUtf("tamper"); //因为返回的是字符串指针,使用我们需要构造一个newStringUtf对象,用来代替这个指针            retval.replace(jstrings); //替换返回值        }    });});"""def printMessage(message,data):    if message['type'] == 'send':        print('[*] {0}'.format(message['payload']))    else:        print(message) process = frida.get_remote_device().attach('com.example.fridasostring')script = process.create_script(jscode)script.on('message',printMessage)script.load()sys.stdin.read()

3. 运行脚本后,点击按钮,我们可以看到字符串已经被替换成了tamper,如下所示:
 
 
 
4. 关于为导出函数的Hook,大体上差不多,差别在于需要通过ida找到偏移值计算地址,而不是像导出函数这么方便罢了,但原理都是差不多的,就不再细说了。
五、相关附件

python Hook代码已经demo下载链接:https://pan.baidu.com/s/1ZCIeJXzeTpQ8uJ9Ew5nnGQ
提取码:z94i
- End -

看雪ID:windy_ll

https://bbs.pediy.com/user-851220.htm 

*本文由看雪论坛 windy_ll 原创,转载请注明来自看雪社区。

推荐文章++++

为了理解反汇编引擎而写的X86/X64反汇编引擎

捆绑包驱动锁首病毒分析

**游戏逆向分析笔记

对宝马车载apps协议的逆向分析研究

x86_64架构下的函数调用及栈帧原理

好书推荐


公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]
“阅读原文”一起来充电吧!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&amp;mid=2458304065&amp;idx=2&amp;sn=8957ce2be3292e3545f26c0796a0a9d6&amp;chksm=b1818ecb86f607dde4119ad86cdbe804f70b73d3f2ac912929ac36f59b25994ca9ba74216be9#rd
如有侵权请联系:admin#unsafe.sh