Frida高級逆向-Hook Java


Frida Hook Java 層

Frida兩種啟動方式的區別

  1. span 模式:frida 重新打開一個進程
    frida -U -f 包名 -l js路徑 --no-pause
  2. attch 模式: 附加在當前打開的進程
    frida -U -l js路徑 --no-pause
    區別就是一個帶 -f 一個不帶

命令行參數詳解

  --version             顯示版本號
  -h, --help            查看幫助
  -D ID, --device=ID    用給定的ID連接到設備
  -U, --usb             連接 USB 設備
  -R, --remote          連接遠程設備
  -H HOST, --host=HOST  連接遠程的設備 地址
  -f FILE, --file=FILE  spawn FILE 模式
  -F, --attach-frontmost
                        attach to frontmost application 附加到最前端的應用程序
  -n NAME, --attach-name=NAME
                        attach to NAME 附加的名稱
  -p PID, --attach-pid=PID
                        attach to PID 附加的進程ID
  --stdio=inherit|pipe  stdio behavior when spawning (defaults to “inherit”)
  --runtime=duk|v8      script runtime to use (defaults to “duk”) 指定js解釋器 duk 或者 v8
  --debug               enable the Node.js compatible script debugger 
  -l SCRIPT, --load=SCRIPT 加載腳本文件
                        load SCRIPT
  -P PARAMETERS_JSON, --parameters=PARAMETERS_JSON
                        Parameters as JSON, same as Gadget
  -C CMODULE, --cmodule=CMODULE
                        load CMODULE
  -c CODESHARE_URI, --codeshare=CODESHARE_URI
                        load CODESHARE_URI
  -e CODE, --eval=CODE  evaluate CODE
  -q                    quiet mode (no prompt) and quit after -l and -e
  --no-pause            automatically start main thread after startup 啟動后自動啟動主線程
  -o LOGFILE, --output=LOGFILE 日志輸出文件
                        output to log file
  --exit-on-error       exit with code 1 after encountering any exception in
                        the SCRIPT 異常退出腳本

Hook一個Java層函數

  • Java.use
    功能:
    動態為className生成一個JavaScript包裝器;可以通過調用$new()來實例化對象來調用構造函數
    參數: className
  • implementaion
    功能: 方法重新實現的屬性
  • overloads
    功能: 重載函數指定類型方法

示例:

function hook_java() {
    // 必須寫在 Java 虛擬機中 
    Java.perform(function() {

        const login = Java.use('com.example.androiddemo.Activity.LoginActivity');
        login.a.overload('java.lang.String', 'java.lang.String').implementation = function(a1, a2) {
            let result = this.a(a1, a2);
            console.log(a1, a2, result);
            return result
        }
    })

}


修改一個函數返回值或參數

示例:

function hook_java() {
    // 必須寫在 Java 虛擬機中 
    Java.perform(function() {

        const login = Java.use('com.example.androiddemo.Activity.LoginActivity');
        const string = Java.use('java.lang.String');
        login.a.overload('java.lang.String', 'java.lang.String').implementation = function(a1, a2) {
            // string int bool 這3種類型 frida 會直接幫我們轉換成 java 類型的
            var result = '這是我修改返回的'

            // 我們自己進行類型轉換
            var result = string.$new("我們自己去轉換的java類型的")

            return result
        }
    })

}

調用靜態函數和非靜態函數

靜態函數和靜態方法可以使用 Java.use 出來的函數直接調用。Java.use 相當於new了一個新的對象
非靜態函數和靜態方法,有兩種使用情況,一種是 Java.use 出來的對象,自己進行實例化 obj.$new() 這種方法需要知道構造參數,比較麻煩。
那么可以使用 Java.choose 該方法是從內存中找到實例化好的類進行調用

示例:

function hook_java() {
    // 必須寫在 Java 虛擬機中 
    Java.perform(function() {

        // 調用靜態方法
        var frida_activate = Java.use('com.example.Frida');
        frida_activate.setStatic_bool)var()

        // 調用非靜態方法
        Java.choose('com.example.androiddemo.Activity.FridaActivity2', {
            // 匹配到的情況下,進行調用
            // 注意: 內存中可以有多個實例化好的類?
            onMatch: function (instance) {
                // 調用方法
                instance.setBool_var()
                // 設置變量值
                instance.static_bool_var.value = true;
            },
            onComplete: function () {

            }
        })

})

}

設置成員變量

設置和函數名相同的成員變量
屬性和函數名重名了,需要在屬性前面 加一個 下划線 _

示例:

function hook_java() {
    // 必須寫在 Java 虛擬機中 
    Java.choose('com.example.androiddemo.Activity.FridaActivity3', {
            onMatch: function (instance) {
                // instance.static_bool_var.value = true;
                instance.bool_var.value = true;
                // TODO 關注一下這個屬性,他跟函數名重名了,需要加一個  _  下划線
                instance._same_name_bool_var.value = true;
                console.log(instance.bool_var.value, instance._same_name_bool_var.value)
            },
            onComplete: function () {

            }
        })

}

Hook內部類,枚舉類的函數

示例:

function call_frida4() {
    // hook 類的多個函數, 內部類
    Java.perform(function () {
        // 這是hook類的 內部類
        const FridaActivity4 = Java.use('com.example.androiddemo.Activity.FridaActivity4$InnerClasses');
        // getDeclaredMethods 獲取當前類的方法   getMethods 獲取當前類以及繼承類的所有方法
        const methods = FridaActivity4.class.getDeclaredMethods();
        for (let method of methods) {
            // console.log(method)
            let method_str = method.toString();
            let mtdsplit = method_str.split('.')
            let meds = mtdsplit[mtdsplit.length - 1].replace('()', '');
            console.log(meds)
            FridaActivity4[meds].implementation = function () {
                return true
            }
        }


    })
}

查找接口,Hook動態加載dex

示例:

function call_frida5() {

    // hook 動態加載的dex 類, 以及查看類的類名

    Java.perform(function () {

        // 1. 嘗試 hook 一下 接口類
        // 會提示 Error: java.lang.ClassNotFoundException:
        // Java.use('com.example.androiddemo.Dynamic.AbstractC0000CheckInterface');

        // 2. 查看動態加載的類名
        const FridaActivity5 = Java.use('com.example.androiddemo.Activity.FridaActivity5');
        FridaActivity5.getDynamicDexCheck.implementation = function () {

            let result = this.getDynamicDexCheck();
            // 查看當前返回值的 類名
            console.log(result.$className)
            return result

        }

        // 這個時候還是 沒有找到類 需要將 類 loader 進來
        // Java.use('com.example.androiddemo.Dynamic.DynamicCheck').check.implementation = function (){
        //     return true
        // }

        // 3. hook 動態加載的 dex
        // 枚舉類加載
        Java.enumerateClassLoaders({
            onMatch: function (loader) {
                console.log(loader)
                try {
                    if (loader.findClass('com.example.androiddemo.Dynamic.DynamicCheck')) {
                        console.log(loader);
                        // 切換classloader
                        Java.classFactory.loader = loader
                    }
                } catch (e) {
                    // console.log(e)

                }


            },
            onComplete: function () {

            }
        })
        // 這個時候再來 hook 這個類
        Java.use('com.example.androiddemo.Dynamic.DynamicCheck').check.implementation = function () {
            return true
        }


    })
}

枚舉class

示例:


function call_frida6() {

    //  hook 多個 class
    // 發現一個關鍵點 就是 當一個類 沒有執行的時候, frida 枚舉是枚舉不出來的。
    Java.perform(function () {
        // 遍歷當前 loader 的 所有類
        Java.enumerateLoadedClasses({
            onMatch: function (name, handle) {
                // console.log(name)
                if (name.indexOf('com.example.androiddemo.Activity.Frida6') >= 0) {
                    console.log(name);
                    Java.use(name).check.implementation = function () {
                        return true;
                    }

                }
            },
            onComplete: function () {

            }
        })


    })
}

Hook 構造函數

$init 表示構造函數

示例:


function call_frida6() {

    Java.perform(function () {
        // $init 表示構造函數
       Java.use('com.example.androiddemo.Dynamic.DynamicCheck').$init.implementation = function (a,b) {
            return this.$init(a,b)
        }


    })
}

打印調用棧

示例:


function show_stack() {
    Java.perform(function () {
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));

    })
}

加載本地DEX

// 打開 dex 文件
var dex = Java.openClassFile('/data/local/tmp/ddex.dex')
Java.perform(function () {
        // 加載 dex
        dex.load()
        // 進行hook
        Java.use('com.tlamb96.kgbmessenger.LoginActivity').j.implementation = function () {
            return true
        }

})



免責聲明!

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



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