frida入門總結


    Frida是一款輕量級HOOK框架,可用於多平台上,例如android、windows、ios等。
    frida分為兩部分,服務端運行在目標機上,通過注入進程的方式來實現劫持應用函數,另一部分運行在系統機器上。
    frida上層接口支持js、python、c等。
    Frida官方github地址為:frida官方github地址

    PS:雖然百度一下會發現frida教程有不少,但是涉及到native層的教程基本很少,然后對每一句Hook代碼解釋一下的更是少之又少,所以我還是厚着臉皮從自己的角度寫了這一篇!!!


0|1二、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命令報錯)。

1.png

    3、安裝frida-tools模塊,命令同上,pip install frida-tools或者python -m pip install frida-tools

2.png

    4、下載運行在目標機上的frida-sever端,官方下載地址:https://github.com/frida/frida/releases,下載時要選擇對應的版本下載,例如我的機器為arm32為架構,就選擇frida-server-12.8.14-android-arm.xz下載。(可以在adb使用命令cat /proc/cpuinfo查詢)

3.png

4.png

    5、將第四步下載好的文件解壓,然后通過命令adb push 你的電腦是存放位置 /data/local/tmp將文件傳輸到手機中,然后通過adb shell進入手機端,給文件賦權777,並於root權限啟動。

5.png

6.png

    6、做完以上幾步后,新開一個命令行輸入命令frida-ps -U查看手機進程,如果出現以下結果,則frida安裝成功。

7.png


0|1三、Frida Hook Java層


    1、編寫一個小demo用來hook,該demo關鍵部分代碼如下:

8.png

    2、現在我們將該apk安裝好,運行看一下未Hook前的顯示字符串!!!

9.png

    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:27043adb forward tcp:27042 tcp:27042來轉發這兩個端口,接着在手機上運行該應用程序,在命令行中執行腳本,最后點擊應用的按鈕,即可看到字符串已經被替換成我們要替換的了!!!

6.png

10.png

11.png

12.png


0|1四、Frida Hook Native層


  4.1、Hook native層返回值為int類型的demo

    1、還是先寫一個小demo,下面貼一下關鍵代碼(很簡單c語言代碼就不再解釋了,至於native層函數怎么編寫,由於本篇主要不是講怎么編寫so函數,就不過多敘述了,實在不會的可以看一下我的一篇博客,我覺得寫得還是挺詳細的,博客編寫native層函數鏈接:https://www.cnblogs.com/aWxvdmVseXc0/p/11564809.html)和未Hook前截圖:

23.png

代碼:

/* 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 __cplusplus extern "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

13.png

14.png

    2、接下來我們來寫python hook腳本,我們需要hook native層這個函數,達到返回值修改為0的效果。寫到這里需要說明一下關於so文件當中的函數,分為導出函數和未導出函數兩種,導出函數打開IDA后能夠在導出表中找到的函數就是導出函數,未導出函數則在導出表中尋找不到,一般來說靜態編寫的native函數都能在導出表中尋找到,而動態加載的則無法在導出表中發現!!!

15.png

代碼如下:(跟上面hook java層重復的代碼不在注釋詳講了!!!)

import frida import 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,效果圖如下:

16.png

17.png

  4.2、Hook native層返回值為String類型的demo

    1、上面已經寫了怎么Hook修改native層函數返回值為int類型的情況,使用replace()函數直接修改即可,但是返回情況為字符串則不一樣,在c語言中,返回值為字符串其實是返回了一個char *(字符串指針),所以簡單的替換是無法取效果的,具體怎么修改返回值,接着看下面,下面還是貼上demo的關鍵代碼和未Hook前截圖:

22.png

代碼如下:

/* 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 __cplusplus extern "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前運行截圖:

18.png

    2、接下來是python Hook腳本(只解釋與上面有差異的代碼),Hook的函數具體函數名還是使用IDA去尋找

19.png

python代碼:

import frida import 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,如下所示:

20.png

21.png

    4、關於為導出函數的Hook,大體上差不多,差別在於需要通過ida找到偏移值計算地址,而不是像導出函數這么方便罷了,但原理都是差不多的,就不在細說了!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM