Hook的新大陸:frida

體驗了一把frida,感覺像是發(fā)現(xiàn)了新大陸一樣,不信你繼續(xù)看~

frida跟xposed對比:
xposed:root + xposed環(huán)境 + 寫xposed模塊
frida:root + 寫js腳本

frida只需要設備有root權限,無需刷xposed環(huán)境,就能實現(xiàn)hook功能,而且不需要重啟App,修改js腳本之后直接注入即可。本文將手把手帶你上手frida。

frida github:
https://github.com/frida/frida

一、準備

frida分客戶端環(huán)境和服務端環(huán)境。

在客戶端我們可以編寫js代碼或者Python代碼,連接遠程設備,提交要注入的代碼到遠程,接受服務端的發(fā)來的消息等。

在服務端,我們需要用Javascript代碼注入到目標進程,操作內(nèi)存數(shù)據(jù),給客戶端發(fā)送消息等操作。我們也可以把客戶端理解成控制端,服務端理解成被控端。

假如我們要用PC來對Android設備上的某個進程進行操作,那么PC就是客戶端,而Android設備就是服務端。

1.1 準備frida服務端環(huán)境

根據(jù)自己的平臺下載frida服務端并解壓
https://github.com/frida/frida/releases

解壓,重命名為 frida-server

電腦連接手機,通過adb執(zhí)行以下命令將服務端推到手機的 /data/local/tmp 目錄

adb push frida-server /data/local/tmp/frida-server

執(zhí)行以下命令修改frida-server文件權限

adb shell chmod 777 /data/local/tmp/frida-server

啟動服務

adb shell
cd /data/local/tmp
su
./frida-server

1.2 準備客戶端環(huán)境

我用的是mac,windows同理,
首先需要python環(huán)境,這個自己安裝,然后通過pip安裝frida

命令如下

pip install frida-tools
pip install frida

等待一會兒,測試frida是否安裝成功


1.3 測試

查看進程

frida-ps -U

參數(shù)解釋:

-U 指定對USB設備操作
-l 指定加載一個Javascript腳本
最后指定一個進程名,如果想指定進程pid,用-p選項。正在運行的進程可以用frida-ps -U命令查看

這個報錯是由于服務端沒啟動,前面的啟動服務是不是沒成功,回去看 1.1節(jié)。
然后在另一個控制臺執(zhí)行 frida-ps -U

可以看到手機正在運行的進程pid都列出來了。

接下來將一個腳本 myhook.js 注入到Android目標進程

frida -U -l myhook.js com.lanshifu.demo_module

成功了,這個myhook.js內(nèi)容如下

if(Java.available){
    Java.perform(function(){
        var MainActivity = Java.use("com.lanshifu.demo_module.ui.activity.DemoMainActivity");
        MainActivity.testCrash.overload("int").implementation=function(chinese,math){
            console.log("[javascript] testCrash method be called.");
            send("hook  testCrash method success>>>");
            return this.testCrash(12345678);      
        }
    });
}

攔截DemoMainActivitytestCrash(int)方法,調(diào)用的時候打印信息并且將入?yún)⒏臑?2345678。日志打印出來了,界面上看也成功了,就不上圖了,下面會詳細介紹hook的各種操作。

1.4 控制腳本命令

frida運行過程中,執(zhí)行%resume重新注入,執(zhí)行%reload來重新加載腳本;執(zhí)行exit結束腳本注入

一般情況下,修改js腳本,然后輸入exit結束腳本注入,再重新輸入注入命令即可

二、Hook 實戰(zhàn)

2.1 載入類

Java.use方法用于聲明一個Java類,在用一個Java類之前首先得聲明。比如聲明一個String類,要指定完整的類名:
var StringClass=Java.use("java.lang.String");

2.2 參數(shù)

修改一個函數(shù)的實現(xiàn)是逆向調(diào)試中相當有用的。修改一個函數(shù)的實現(xiàn)后,如果這個函數(shù)被調(diào)用,我們的Javascript代碼里的函數(shù)實現(xiàn)也會被調(diào)用。

參數(shù)類型表示(跟JNI里面的方法簽名基本一樣)
  1. 對于基本類型,直接用它在Java中的表示方法就可以了,不用改變,例如:
    int
    short
    char
    byte
    boolean
    float
    double
    long

  2. 基本類型數(shù)組,用左中括號接上基本類型的縮寫

基本類型 縮寫:
boolean: Z
byte: B
char: C
double: D
float: F
int: I
long: J
short: S

例如:int[]類型,在重載時要寫成[I

  1. 任意類,直接寫完整類名即可

例如:java.lang.String

  1. 對象數(shù)組,用左中括號接上完整類名再接上分號

例如:[java.lang.String;

2.3 hook 無參構造函數(shù)

//聲明一個Java類
var MyClass = Java.use("com.lanshifu.demo_module.ui.activity.DemoHookTestActivity$MyClass");
        
//hook 無參構造
MyClass.$init.overload().implementation=function(){
     //調(diào)用原來構造
     this.$init();
     send("hook 無參構造 ");
 }

2.3 hook 有參構造函數(shù)

var MyClass = Java.use("com.lanshifu.demo_module.ui.activity.DemoHookTestActivity$MyClass");
 //hook 有參構造,入?yún)⑹?int[]
MyClass.$init.overload('[I').implementation=function(param){
     send("hook  有參構造 init(int[] i) method ");
}

2.4 hook 多參數(shù)的構造函數(shù)的實現(xiàn)

ClassName.$init.overload('[B','int','int').implementation=function(param1,param2,param3){
    //do something
}

注意:當構造函數(shù)(函數(shù))有多種重載形式,比如一個類中有兩個形式的func:void func()和void func(int),要加上overload來對函數(shù)進行重載,否則可以省略overload

2.5 hook 一般函數(shù)

 //void函數(shù)
MyClass.method1.overload().implementation=function(){
    send("hook  method1  ");
}
        
//有入?yún)⒌暮瘮?shù)
MyClass.method2.overload("int","int").implementation=function(param1,param2){
     send("hook  method2  ");
     this.method2(100,100)
}
        

2.6 調(diào)用函數(shù)

和Java一樣,創(chuàng)建類實例就是調(diào)用構造函數(shù),而在這里用$new表示一個構造函數(shù)。

//實例化一個類并調(diào)用它的method3方法
var ClassName=Java.use("com.lanshifu.demo_module.ui.activity.DemoHookTestActivity$MyClass");
var instance = ClassName.$new();
instance.method3(1,2,3);

2.7 類型轉換

用Java.cast方法來對一個對象進行類型轉換,如將variable轉換成java.lang.String:

var StringClass=Java.use("java.lang.String");
var NewTypeClass=Java.cast(variable,StringClass);

2.8 Java.perform方法

Java.perform(fn)在Javascript代碼成功被附加到目標進程時調(diào)用,我們核心的代碼要在里面寫。格式:

Java.perform(function(){
//do something...
});

三、配置python腳本注入

3.1 創(chuàng)建 FridaDemo.py

我直接在Pycharm 里面創(chuàng)建了 FridaDemo.py,然后代碼如下

# -*- coding: UTF-8 -*-

import frida, sys

jscode = """
if(Java.available){
    Java.perform(function(){
        var MainActivity = Java.use("com.lanshifu.demo_module.ui.activity.DemoMainActivity");
        
        MainActivity.testCrash.overload("int").implementation=function(chinese,math){
            console.log("[javascript] testCrash method be called.");
            send("hook  testCrash method success>>>");
            return this.testCrash(12345678);      
        }
        
        //聲明一個Java類
        var MyClass = Java.use("com.lanshifu.demo_module.ui.activity.DemoHookTestActivity$MyClass");
        
        //hook 無參構造
        MyClass.$init.overload().implementation=function(){
                //調(diào)用原來構造
                this.$init();
                send("hook 無參構造 ");
        }
        
        //hook 有參構造,入?yún)⑹?int[]
        MyClass.$init.overload('[I').implementation=function(param){
             send("hook  有參構造 init(int[] i) method ");
        }
        
        //hook 多個參數(shù)構造,入?yún)⑹?int,int
        MyClass.$init.overload("int","int").implementation=function(param1,param2){
             send("hook  success  ");
             send(param1);
             send(param2);
             //修改返回值
             return 100;
        }
        
        //void函數(shù)
        MyClass.method1.overload().implementation=function(){
            send("hook  method1  ");
            this.method1();

        }
        
        //有入?yún)⒌暮瘮?shù)
        MyClass.method2.overload("int","int").implementation=function(param1,param2){
            send("hook  method2  ");
            
            //實例化一個類并調(diào)用它的method3方法
            var ClassName=Java.use("com.lanshifu.demo_module.ui.activity.DemoHookTestActivity$MyClass");
           var instance = ClassName.$new();
           instance.method3(1,2,3);
        
            this.method2(100,100)
        }
        
        //
        MyClass.method3.overload("int","int","int").implementation=function(param1,param2,param3){
            send("hook  method3  ");
            this.method3(100,100,100)
        }
        
        
    });
}
"""

def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)
pass

# 查找USB設備并附加到目標進程
session = frida.get_usb_device().attach('com.lanshifu.demo_module')
# 在目標進程里創(chuàng)建腳本
script = session.create_script(jscode)
# 注冊消息回調(diào)
script.on('message', on_message)
print('[*] Start attach')
# 加載創(chuàng)建好的javascript腳本
script.load()
# 讀取系統(tǒng)輸入
sys.stdin.read()

執(zhí)行這個python腳本,手機打開app執(zhí)行到該方法,看到打印了日志


ctrl + c停止腳本,看起來方便一些。

接下來分析一下步驟:

  1. 通過調(diào)用frida.get_usb_device()方法來得到一個連接中的USB設備(Device類)實例
  2. 調(diào)用attach附加到目標進程
  3. 調(diào)用Session類的create_script()方法創(chuàng)建一個腳本,傳入需要注入的javascript代碼并得到Script類實例
  4. 調(diào)用Script類的on()方法添加一個消息回調(diào),第一個參數(shù)是信號名,乖乖傳入message就行,第二個是回調(diào)函數(shù)
  5. 最后調(diào)用Script類的load()方法來加載剛才創(chuàng)建的腳本。

四、總結

  1. 手機配置frida 服務端環(huán)境
  2. 電腦配置frida 客戶端環(huán)境
  3. 編寫js腳本
  4. 通過adb啟動服務,adb shell 'su -c /data/local/tmp/frida-server'
  5. 電腦執(zhí)行腳本:frida -U -l myhook.js com.lanshifu.demo_module
  6. 在命令行輸入exit,回車,停止注入代碼

體驗了一把frida之后, 發(fā)現(xiàn)一個很明顯的優(yōu)勢,就是不需要寫xposed模塊,直接一個js腳本,就能馬上測試hook點,不需要重啟應用。

手機frida服務端的配置踩了一個坑,下載錯了,我的6.0 手機是arm架構的,我下載了arm64的,導致注入js之后手機崩潰。


本文參考:
http://www.itdecent.cn/p/f98aca8f3c05
https://www.frida.re/docs/examples/android/

如有雷同,純屬copy。

我的簡書主頁:
藍師傅_Android

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 如需轉載請注明出處 by SimonKoh 0x01 前言 關于android的hook以前一直用的xposed來...
    SimonKoh閱讀 70,360評論 5 21
  • frida是一款方便并且易用的跨平臺Hook工具,使用它不僅可以Hook Java寫的應用程序,而且還可以Hook...
    luoyesiqiu閱讀 17,253評論 1 11
  • 0x01 簡介 frida 是一款基于 python+javascript 的 hook 框架,可運行在 andr...
    simplehych閱讀 51,545評論 13 39
  • 0x0 零 Hook是我們常用的一種技術手段,在開發(fā)中,也經(jīng)??吹絊elf-Hook等操作,而在逆向分析中,Hoo...
    老江_閱讀 122,456評論 1 7
  • 我想告訴你我追求的,缺只是我在追求著,我想給你去我不曾擁有的力量,但只是我一廂情愿罷了,奈何天地間,山河戀,渡過難...
    酷起閱讀 202評論 0 0

友情鏈接更多精彩內(nèi)容