亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Frida Java Hook示例分析

發布時間:2021-11-24 14:27:50 來源:億速云 閱讀:197 作者:iii 欄目:大數據

這篇文章主要講解了“Frida Java Hook示例分析”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Frida Java Hook示例分析”吧!

1.1 Java層攔截內部類函數

HOOKAndroid逆向中,我們也會經常遇到在Java層的內部類。Java內部類函數,使得我們更難以分析代碼。我們在這章節中對內部類進行一個基本了解和使用FRIDA對內部類進行鉤子攔截處理。什么是內部類?所謂內部類就是在一個類內部進行其他類結構的嵌套操作,它的優點是內部類與外部類可以方便的訪問彼此的私有域(包括私有方法、私有屬性),所以Android中有很多的地方都會使用到內部類,我們來見一個例子也是最直觀的,如下圖4-17。<br>Frida Java Hook示例分析

圖4-17 User類中的clz類<br>在圖4-17中看到User類中嵌套了一個clz,這樣的操作也是屢見不鮮了。在frida中,我們可以使用$符號對起進行處理。首先打開jadxgui軟件對代碼進行反編譯,反編譯之后進入User類,下方會有一個smali的按鈕,點擊smali則會進入smali代碼,進入smali代碼直接按ctrl+f局部搜索字符串clz,因為clz是內部類的名稱,那么就會搜到Lcom/roysue/roysueapplication/User\$clz;,我們將翻譯成java代碼就是:com.roysue.roysueapplication.User\$clz,去掉第一個字符串的L/以及;就構成了內部類的具體類名了,見下圖4-18。<br>Frida Java Hook示例分析Frida Java Hook示例分析<br>圖4-18 smali代碼<br>經過上面的分析我們已經得知最重要的部分類的路徑:com.roysue.roysueapplication.User\$clz,現在來對內部類進行HOOK,現在開始編寫js腳本。

1.1.1 攔截內部類函數代碼示例

function hook_overload_3() {
    if(Java.available) {
        Java.perform(function () {
            console.log("start hook");
            //注意此處類的路徑填寫更改所分析的路徑
            var clz = Java.use('com.roysue.roysueapplication.User$clz');
            if(clz != undefined) {
                //這邊也是像正常的函數來hook即可
                clz.toString.implementation = function (){
                    console.log("成功hook clz類");
                    return this.toString();
                }
            } else {
                console.log("clz: undefined");
            }
            console.log("start end");
        });
    }
}

執行腳本之后,我們可以看到控制也已經成功附加并且打印了成功hook clz類,這樣我們也能夠對Java層的內部類進行處理了。

[Google Pixel::com.roysue.roysueapplication]-> 成功hook clz類
成功hook clz類

1.2 Java層枚舉所有的類并定位類

在前面我們學會了如何在java層的各種函數的HOOK操作了,現在開始學習枚舉所有的類并定位類的騷套路了~,學習之前我們要了解API中的enumerateLoadedClasses方法,它是屬于Java對象中的一個方法。能夠枚舉現在加載的所有類,enumerateLoadedClasses存在2個回調函數,分別是onMatch:function(ClassName):為每個加載的具有className的類調用,每個ClassName返回來的都是一個類名;和onComplete:function():在枚舉所有類枚舉完之后回調一次。

1.2.1 枚舉所有的類并定位類代碼示例

setTimeout(function (){
  Java.perform(function (){
    console.log("n[*] enumerating classes...");
    //Java對象的API enumerateLoadedClasses
    Java.enumerateLoadedClasses({
      //該回調函數中的_className參數就是類的名稱,每次回調時都會返回一個類的名稱
      onMatch: function(_className){
        //在這里將其輸出
        console.log("[*] found instance of '"+_className+"'");

        //如果只需要打印出com.roysue包下所有類把這段注釋即可,想打印其他的替換掉indexOf中參數即可定位到~
        //if(_className.toString().indexOf("com.roysue")!=-1)
        //{
        //    console.log("[*] found instance of '"+_className+"'");
        //}
      },
      onComplete: function(){
        //會在枚舉類結束之后回調一次此函數
        console.log("[*] class enuemration complete");
      }
    });
  });
});

當我們執行該腳本時,注入目標進程之后會開始調用onMatch函數,每次調用都會打印一次類的名稱,當onMatch函數回調完成之后會調用一次onComplete函數,最后會打印出class enuemration complete,見下圖。<br>Frida Java Hook示例分析<br>圖4-19 枚舉所有類

1.3 Java層枚舉類的所有方法并定位方法

上文已經將類以及實例枚舉出來,接下來我們來枚舉所有方法,打印指定類或者所有的類的內部方法名稱,主要核心功能是通過類的反射方法中的getDeclaredMethods(),該api屬于JAVAJDK中自帶的API,屬于java.lang.Class包中定義的函數。該方法獲取到類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。當然也包括它所實現接口的方法。在Java中它是這樣定義的:public Method[] getDeclaredMethods();其返回值是一個Method數組,Method實際上就是一個方法名稱字符串,當然也是一個對象數組,然后我們將它打印出來。

1.3.1 枚舉類的所有方法并定位方法代碼示例

function enumMethods(targetClass)
{
    var hook = Java.use(targetClass);
    var ownMethods = hook.class.getDeclaredMethods();
    hook.$dispose;
    return ownMethods;
}

function hook_overload_5() {
    if(Java.available) {
        Java.perform(function () {
           var a = enumMethods("com.roysue.roysueapplication.User$clz")
           a.forEach(function(s) {
                console.log(s);
           });
        });
    }
}

我們先定義了一個enumMethods方法,其參數targetClass是類的路徑名稱,用于Java.use獲取類對象本身,獲取類對象之后再通過其.class.getDeclaredMethods()方法獲取目標類的所有方法名稱數組,當調用完了getDeclaredMethods()方法之后再調用$dispose方法釋放目標類對象,返回目標類所有的方法名稱、返回類型以及函數的權限,這是實現獲取方法名稱的核心方法,下面一個方法主要用于注入到目標進程中去執行邏輯代碼,在hook_overload_5方法中先是使用了Java.perform方法,再在內部調用enumMethods方法獲取目標類的所有方法名稱、返回類型以及函數的權限,返回的是一個Method數組,通過forEach迭代器循環輸出數組中的每一個值,因為其本身實際就是一個字符串所以直接輸出就可以得到方法名稱,腳本執行效果如下圖4-20。<br>Frida Java Hook示例分析Frida Java Hook示例分析<br>圖4-20 腳本執行后效果在圖4-17中clz只有一個toString方法,我們填入參數為com.roysue.roysueapplication.User$clz,就能夠定位到該類中所有的方法。

1.4 Java層攔截方法的所有方法重載

我們學會了枚舉所有的類以及類的有方法之后,那我們還想知道如何獲取所有的方法重載函數,畢竟在Android反編譯的源碼中方法重載不在少數,對此,一次性hook所有的方法重載是非常有必要的學習。我們已經知道在hook重載方法時需要寫overload('x'),也就是說我們需要構造一個重載的數組,并把每一個重載都打印出來。

1.4.1 攔截方法的所有方法重載代碼示例

function hook_overload_8() {
    if(Java.available) {
        Java.perform(function () {
            console.log("start hook");
            var targetMethod = 'add';
            var targetClass = 'com.roysue.roysueapplication.Ordinary_Class';
            var targetClassMethod = targetClass + '.' + targetMethod;
            //目標類
            var hook = Java.use(targetClass);
            //重載次數
            var overloadCount = hook[targetMethod].overloads.length;
            //打印日志:追蹤的方法有多少個重載
            console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]");
            //每個重載都進入一次
            for (var i = 0; i < overloadCount; i++) {
                    //hook每一個重載
                    hook[targetMethod].overloads[i].implementation = function() {
                        console.warn("n*** entered " + targetClassMethod);
                        //可以打印每個重載的調用棧,對調試有巨大的幫助,當然,信息也很多,盡量不要打印,除非分析陷入僵局
                        Java.perform(function() {
                            var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
                                console.log("nBacktrace:n" + bt);
                        });   
                        // 打印參數
                        if (arguments.length) console.log();
                        for (var j = 0; j < arguments.length; j++) {
                            console.log("arg[" + j + "]: " + arguments[j]);
                        }
                        //打印返回值
                        var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?)
                        console.log("nretval: " + retval);
                        console.warn("n*** exiting " + targetClassMethod);
                        return retval;
                    }
                }
            console.log("hook end");
        });
    }
}

1.4.2 攔截方法的所有方法重載代碼示例詳解

上面這段代碼可以打印出com.roysue.roysueapplication.Ordinary_Class類中add方法重載的個數以及hook該類中所有的方法重載函數,現在來剖析上面的代碼為什么可以對一個類中的所有的方法重載HOOK掛上鉤子。首先我們定義了三個變量分別是targetMethod、targetClass、targetClassMethod,這三個變量主要于定義方法的名稱、類名、以及類名+方法名的賦值,首先使用了Java.use獲取了目標類對象,再獲取重載的次數。這里詳細說一下如何獲取的:var method_overload = cls[<func_name>].overloads[index];這句代碼可以看出通過cls索引func_name到類中的方法,而后面寫到overloads[index]是指方法重載的第index個函數,大致意思就是返回了一個method對象的第index位置的函數。而在代碼中寫道:var overloadCount = hook[targetMethod].overloads.length;,采取的方法是先獲取類中某個函數所有的方法重載個數。繼續往下走,開始循環方法重載的函數,剛剛開始循環時hook[targetMethod].overloads[i].implementation這句對每一個重載的函數進行HOOK。這里也說一下Arguments:Argumentsjs中的一個對象,js內的每個函數都會內置一個Arguments對象實例arguments,它引用著方法實參,調用其實例對象可以通過arguments[]下標的來引用實際元素,arguments.length為函數實參個數,arguments.callee引用函數自身。這就是為什么在該段代碼中并看不到arguments的定義卻能夠直接調用的原因,因為它是內置的一個對象。好了,講完了arguments咱們接著說,打印參數通過arguments.length來循環以及arguments[j]來獲取實際參數的元素。那現在來看applyapplyjs中是怎么樣的存在,apply的含義是:應用某一對象的一個方法,用另一個對象替換當前對象,this[targetMethod].apply(this, arguments);這句代碼簡言之就是執行了當前的overload方法。執行完當前的overload方法并且打印以及返回給真實調用的函數,這樣不會使程序錯誤。那么最終執行效果見下圖4-21:<br>Frida Java Hook示例分析Frida Java Hook示例分析<br>圖4-21 終端顯示<br>可以看到成功打印了add函數的方法重載的數量以及hook打印出來的參數值、返回值!

1.5 Java層攔截類的所有方法

學會了如何HOOK所有方法重載函數后,我們可以把之前學習的整合到一起,來hook指定類中的所有方法,也包括方法重載的函數。下面js中核心代碼是利用重載函數的特點來HOOK全部的方法,普通的方法也是一個特殊方法重載,只是它只是一個方法而已,直接把它當作方法重載來HOOK就好了,打個比方正方形是特殊的長方形,而長方形是不是特殊的正方形。這個正方形是普通函數,而長方形是重載方法這樣大家應該很好理解了~在上一章節中已經知道了如何hook方法重載,只是方法名稱和類名是寫死的,只需要把成員的targetClass、targetMethod定義方法中的參數即可,在該例子中拿到指定類所有的所有方法名稱,更加靈活使用了,代碼如下。

1.5.1 攔截類的所有方法代碼示例

function traceClass(targetClass)
{
    //Java.use是新建一個對象哈,大家還記得么?
    var hook = Java.use(targetClass);
    //利用反射的方式,拿到當前類的所有方法
    var methods = hook.class.getDeclaredMethods();
    //建完對象之后記得將對象釋放掉哈
    hook.$dispose;
    //將方法名保存到數組中
    var parsedMethods = [];
    methods.forEach(function(method) {
        //通過getName()方法獲取函數名稱
        parsedMethods.push(method.getName());
    });
    //去掉一些重復的值
    var targets = uniqBy(parsedMethods, JSON.stringify);
    //對數組中所有的方法進行hook
    targets.forEach(function(targetMethod) {
        traceMethod(targetClass + "." + targetMethod);
    });
}
function hook_overload_9() {
    if(Java.available) {
        Java.perform(function () {
            console.log("start hook");
            traceClass("com.roysue.roysueapplication.Ordinary_Class");
            console.log("hook end");
        });
    }
}
s1etImmediate(hook_overload_9);

執行腳本效果可以看到,hook到了com.roysue.roysueapplication.Ordinary_Class類中所有的函數,在執行其被hook攔截的方法時候,也打印出了每個方法相應的的參數以及返回值,見下圖4-22。<br>Frida Java Hook示例分析<br>圖4-22 終端運行顯示效果

1.6 Java層攔截類的所有子類

這里的核心功能也用到了上一小章節中定義的traceClass函數,該函數只需要傳入一個class路徑即可對class中的函數完成注入hook。那么在本小章節來hook掉所有類的子類,使我們的腳本更加的靈活方便。通過之前的學習我們已經知道enumerateLoadedClasses這個api可以枚舉所有的類,用它來獲取所有的類然后再調用traceClass函數就可以對所有類的子進行全面的hook。但是一般不會hook所有的函數,因為AndroidAPI函數實在太多了,在這里我們需要匹配自己需要hook的類即可,代碼如下。

//枚舉所有已經加載的類
Java.enumerateLoadedClasses({
    onMatch: function(aClass) {
        //迭代和判斷
        if (aClass.match(pattern)) {
            //做一些更多的判斷,適配更多的pattern
            var className = aClass.match(/[L]?(.*);?/)[1].replace(///g, ".");
            //進入到traceClass里去
            traceClass(className);
        }
    },
    onComplete: function() {}
});

1.7 RPC遠程調用Java層函數

FRIDA中,不但提供很完善的HOOK機制,并且還提供rpc接口。可以導出某一個指定的函數,實現在python層對其隨意的調用,而且是隨時隨地想調用就調用,極其方便,因為是在供給外部的python,這使得rpc提供的接口可以與python完成一些很奇妙的操作,這些導出的函數可以是任意的java內部的類的方法,調用我們自己想要的對象和特定的方法。那我們開始動手吧,現在我們來通過RPC的導出功能將圖4-9中的add方法供給外部調用,開始編寫rpc_demo.py文件,這次是python文件了哦~不是js文件了

1.7.1 rpc導出Java層函數代碼示例

import codecs
import frida
from time import sleep

# 附加進程名稱為:com.roysue.roysueapplication
session = frida.get_remote_device().attach('com.roysue.roysueapplication')

# 這是需要執行的js腳本,rpc需要在js中定義
source = """
    //定義RPC
    rpc.exports = {
        //這里定義了一個給外部調用的方法:sms
        sms: function () {
            var result = "";
            //嵌入HOOK代碼
            Java.perform(function () {
                //拿到class類
                var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");
                //最終rpc的sms方法會返回add(1,3)的結果!
                result = Ordinary_Class.add(1,3);
             });
            return result;
        },
    };
"""

# 創建js腳本
script = session.create_script(source)
script.load()

# 這里可以直接調用java中的函數
rpc = script.exports
# 在這里也就是python下直接通過rpc調用sms()方法
print(rpc.sms())
sleep(1)

session.detach()

當我們執行python rpc_demo.py時先會創建腳本并且注入到目標進程,在上面的source實際上就是js邏輯代碼了。在js代碼內我們定義了rpc可以給python調用的sms函數,而sms函數內部嵌套調用Java.perform再對需要拿到的函數的類進行主動調用,把最終的結果返回作為sms的返回值,當我們在python層時候可以任意調用sms中的原型add方法~

1.8 綜合案例一:在安卓8.1上dump藍牙接口和實例

一個比較好的綜合案例 :dump藍牙信息的“加強版”——BlueCrawl

VERSION="1.0.0"
setTimeout(function(){
    Java.perform(function(){
        Java.enumerateLoadedClasses({
                onMatch: function(instance){
                    if (instance.split(".")[1] == "bluetooth"){
                        console.log("[->]t"+lightBlueCursor()+instance+closeCursor());
                    }
                },
                onComplete: function() {}
            });

        Java.choose("android.bluetooth.BluetoothGattServer",{
                onMatch: function (instance){
                    ...
                onComplete: function() { console.log("[*] -----");}
            });

        Java.choose("android.bluetooth.BluetoothGattService",{
                onMatch: function (instance){
                    ...
                onComplete: function() { console.log("[*] -----");}
            });

         Java.choose("android.bluetooth.BluetoothSocket",{
                onMatch: function (instance){
                    ...
                onComplete: function() { console.log("[*] -----");}
            });

          Java.choose("android.bluetooth.BluetoothServerSocket",{
                onMatch: function (instance){
                    ...
                onComplete: function() { console.log("[*] -----");}
            });

          Java.choose("android.bluetooth.BluetoothDevice",{
                onMatch: function (instance){
                    ...
                onComplete: function() { console.log("[*] -----");}
            });
    });
},0);

該腳本首先枚舉了很多藍牙相關的類,然后choose了很多類,包括藍牙接口信息以及藍牙服務接口對象等,還加載了內存中已經分配好的藍牙設備對象,也就是上文我們已經演示的信息。我們可以用這個腳本來“查看”App加載了哪些藍牙的接口,App是否正在查找藍牙設備、或者是否竊取藍牙設備信息等。在電腦上運行命令:$ frida -U -l bluecrawl-1.0.0.js com.android.bluetooth執行該腳本時會詳細打印所有藍牙接口信息以及服務接口對象~~

1.9 綜合案例二:動靜態結合逆向WhatsApp

我們來試下它的幾個主要的功能,首先是本地庫的導出函數。

setTimeout(function() {
    Java.perform(function() {
        trace("exports:*!open*");
        //trace("exports:*!write*");
        //trace("exports:*!malloc*");
        //trace("exports:*!free*");
    });
}, 0);

我們hook的是open()函數,跑起來看下效果:<br>

$ frida -U -f com.whatsapp -l raptor_frida_android_trace_fixed.js --no-pause

如圖所示*!open*根據正則匹配到了openlogopen64等導出函數,并hook了所有這些函數,打印出了其參數以及返回值。接下來想要看哪個部分,只要扔到jadx里,靜態“分析”一番,自己隨便翻翻,或者根據字符串搜一搜。比如說我們想要看上圖中的com.whatsapp.app.protocol包里的內容,就可以設置trace("com.whatsapp.app.protocol")。可以看到包內的函數、方法、包括重載、參數以及返回值全都打印了出來。這就是frida腳本的魅力。當然,腳本終歸只是一個工具,你對Java、安卓App的理解,和你的創意才是至關重要的。接下來可以搭配Xposed module看看別人都給whatsapp做了哪些模塊,hook的哪些函數,實現了哪些功能,學習自己寫一寫。

感謝各位的閱讀,以上就是“Frida Java Hook示例分析”的內容了,經過本文的學習后,相信大家對Frida Java Hook示例分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

和林格尔县| 通州市| 逊克县| 称多县| 大同县| 金乡县| 武平县| 尼木县| 河源市| 宁津县| 库尔勒市| 内乡县| 庆元县| 尼木县| 大关县| 伊金霍洛旗| 乡城县| 尉犁县| 萝北县| 桐乡市| 海门市| 南通市| 平乡县| 手机| 定边县| 雅江县| 山东省| 江达县| 玉林市| 十堰市| 抚宁县| 凉山| 武宣县| 宝丰县| 额尔古纳市| 时尚| 石渠县| 南陵县| 临泽县| 淅川县| 阿勒泰市|