国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)

這篇具有很好參考價(jià)值的文章主要介紹了Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

  • Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)

    • 為什么要補(bǔ)環(huán)境

    • Unidbg補(bǔ)環(huán)境的案例情景復(fù)現(xiàn)

    • 模擬執(zhí)行so

      • 參數(shù)獲取

      • unidbg 代碼初始化

      • 目標(biāo)函數(shù)的調(diào)用

      • 補(bǔ)環(huán)境說(shuō)明

      • 實(shí)戰(zhàn)補(bǔ)環(huán)境

    • 本章小節(jié)

Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)

Unidbg是一個(gè)基于unicorn的逆向工具,可以黑盒調(diào)用安卓和iOS中的so文件。這使得逆向人員可以在無(wú)需了解so內(nèi)部算法原理的情況下,主動(dòng)調(diào)用so中的函數(shù),讓其中的算法“為我所用”,只需要傳入所需的參數(shù)、補(bǔ)全運(yùn)行所需的環(huán)境,即可運(yùn)行出所需要的結(jié)果。及由此衍生的輔助分析、算法還原、SO調(diào)試與逆向等等功能。

對(duì)于Android逆向來(lái)說(shuō),Unidbg的特點(diǎn)有以下幾種:

  1. 模擬JNI調(diào)用的API,因此可以調(diào)用JNI_OnLoad函數(shù)。

  2. 支持JavaVMJNIEnv。

  3. 支持模擬系統(tǒng)調(diào)用指令。

  4. 支持ARM32ARM64。

  5. 支持基于Dobby的inline hook。

  6. 支持基于xHook的GOT hook。

  7. unicorn后端支持簡(jiǎn)單的控制臺(tái)調(diào)試器,gdb stub,指令追蹤和內(nèi)存讀寫(xiě)追蹤。

  8. 支持dynarmic快速的后端。

為什么要補(bǔ)環(huán)境

使用unidbg最主要的問(wèn)題就是補(bǔ)環(huán)境,補(bǔ)環(huán)境對(duì)于so的模擬執(zhí)行太重要了,并且在這塊很容易跌跟頭。我們知道unidbg的作用是模擬執(zhí)行so中的函數(shù),也就是使用C/C++編寫(xiě)的函數(shù),它處于Native層。而Native的函數(shù)是Java層的函數(shù)通過(guò)JNI調(diào)用起來(lái)的,
那么Native也可以通過(guò)JNI這座橋梁去調(diào)用Java層的函數(shù)。

在Native層調(diào)用Java層的函數(shù)的時(shí)候,unidbg中并沒(méi)有這些函數(shù)的實(shí)現(xiàn),那么這些so就無(wú)法正常的通過(guò)unidbg加載起來(lái)。所以我們需要手動(dòng)的把Java層的函數(shù)補(bǔ)充起來(lái),讓Native層的函數(shù)去調(diào)用。

PS:以下所有分析均在r0env2022版安卓逆向環(huán)境下完成。r0env2022版集成了Unidbg,打開(kāi)終端輸入unidbg回車(chē),就是一個(gè)安裝好所有依賴(lài)包的可以直接跑項(xiàng)目的完整的Unidbg運(yùn)行環(huán)境。

PS2:案例涉及的代碼及附件會(huì)放在我的Github中,地址:https://github.com/r0ysue/AndroidSecurityStudy

Unidbg補(bǔ)環(huán)境的案例情景復(fù)現(xiàn)

為了給大家講清本章的內(nèi)容,筆者開(kāi)發(fā)了一個(gè)樣本APK構(gòu)造了一些環(huán)境問(wèn)題。首先我們先熟悉一下這個(gè)APP。APP的打開(kāi)后的界面如圖1所示:

Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
圖1 樣本放置的目錄

屏幕中央顯示了一串字符,感覺(jué)像是16進(jìn)制。然后,我們使用Jadx-gui反編譯APK,其中MainActivity.java的代碼如下所示:

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;

    // 檢測(cè)文件
    public native void detectFile();

    // 檢測(cè)是否有Hook
    public native void detectHookTool();

    // native函數(shù),獲取哈希結(jié)果
    public native String getHash(String str);

    // 加載 so
    static {
        System.loadLibrary("dogpro");
    }

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding inflate = ActivityMainBinding.inflate(getLayoutInflater());
        this.binding = inflate;
        setContentView(inflate.mo170getRoot());
        TextView tv = this.binding.sampleText;
        detectFile();
        detectHookTool();
        // 獲取Hash結(jié)果
        String r1 = getHash(getApplicationContext().getPackageCodePath());
        tv.setText(r1);
    }
}

在onCreate中有兩個(gè)檢測(cè),我們先不要理會(huì),他暫時(shí)不會(huì)對(duì)我們本章的內(nèi)容產(chǎn)生任何的影響。但是可以給大家看看他們做了什么事情:

  • detectFile

    int __fastcall Java_com_example_dogpro_MainActivity_detectFile(_JNIEnv *a1)
    {
    int v2; // [sp+8h] [bp-30h]
    int v3; // [sp+Ch] [bp-2Ch]
    int v4; // [sp+14h] [bp-24h]
    int MethodID; // [sp+18h] [bp-20h]
    int v6; // [sp+1Ch] [bp-1Ch]
    int v7; // [sp+20h] [bp-18h]
    int Class; // [sp+24h] [bp-14h]

    // 反射去Java層找File類(lèi)
    Class = _JNIEnv::FindClass(a1, "java/io/File");
    v7 = _JNIEnv::AllocObject(a1, Class);
    // 檢測(cè)的路徑
    v6 = _JNIEnv::NewStringUTF(a1, "/sys/class/power_supply/battery/voltage_now");
    MethodID = _JNIEnv::GetMethodID(a1, Class, "<init>", "(Ljava/lang/String;)V");
    _JNIEnv::CallVoidMethod(a1, v7, MethodID, v6);
    v4 = _JNIEnv::GetMethodID(a1, Class, "exists", "()Z");
    if ( (unsigned __int8)_JNIEnv::CallBooleanMethod(a1, v7, v4) )
    _android_log_print(6, "lilac", byte_35D7);
    else
    _android_log_print(6, "lilac", byte_35F0);
    v3 = _JNIEnv::AllocObject(a1, Class);
    v2 = _JNIEnv::NewStringUTF(a1, "/data/local/tmp/nox");
    _JNIEnv::CallVoidMethod(a1, v3, MethodID, v2);
    if ( (unsigned __int8)_JNIEnv::CallBooleanMethod(a1, v3, v4) )
    return _android_log_print(6, "lilac", byte_361D);
    else
    return _android_log_print(6, "lilac", byte_3636);
    

    }

首先檢測(cè)了電池的相關(guān)信息,我們嘗試去/sys/class/power_supply/battery/voltage_now下查看,如圖2所示:

Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
圖21-2 電池屬性

其它文件表示的含義如下所示:

//電池充電狀態(tài)
cat /sys/class/power_supply/battery/status

//電池電量
cat /sys/class/power_supply/battery/capacity

//電池運(yùn)行狀況
cat /sys/class/power_supply/battery/health

//顯示電池溫度
cat /sys/class/power_supply/battery/temp

//電池電壓 mV
cat /sys/class/power_supply/battery/voltage_now

第二處檢測(cè)的是/data/local/tmp/nox,nox是夜神模擬器,模擬器創(chuàng)建的時(shí)候會(huì)在此路徑有文件的創(chuàng)建。幸運(yùn)的是,當(dāng)檢測(cè)到的時(shí)候,并不會(huì)有任何的操作,所以我們不予理會(huì),這里只帶領(lǐng)大家看看它是如何做檢測(cè)的。

  • detectHookTool

    int __fastcall Java_com_example_dogpro_MainActivity_detectHookTool(_JNIEnv *a1)
    {
    int v1; // r0
    int v2; // r0
    const char *StringUTFChars; // [sp+28h] [bp-A0h]
    int ObjectClass; // [sp+34h] [bp-94h]
    int ObjectArrayElement; // [sp+38h] [bp-90h]
    int i; // [sp+3Ch] [bp-8Ch]
    int ArrayLength; // [sp+40h] [bp-88h]
    int v9; // [sp+44h] [bp-84h]
    int v10; // [sp+48h] [bp-80h]
    int v11; // [sp+4Ch] [bp-7Ch]
    int MethodID; // [sp+50h] [bp-78h]
    int Class; // [sp+54h] [bp-74h]
    size_t n; // [sp+6Ch] [bp-5Ch]
    size_t v16; // [sp+7Ch] [bp-4Ch]
    char v17[24]; // [sp+80h] [bp-48h] BYREF
    char v18[36]; // [sp+98h] [bp-30h] BYREF

    // 反射找到 Throwable => 異常處理
    Class = _JNIEnv::FindClass(a1, "java/lang/Throwable");
    MethodID = _JNIEnv::GetMethodID(a1, Class, "<init>", "()V");
    v11 = _JNIEnv::NewObject(a1, Class, MethodID);
    // 獲取異常堆棧
    v10 = _JNIEnv::GetMethodID(a1, Class, "getStackTrace", "()[Ljava/lang/StackTraceElement;");
    // 調(diào)用方法
    v9 = _JNIEnv::CallObjectMethod(a1, v11, v10);
    ArrayLength = _JNIEnv::GetArrayLength(a1, v9);
    // 復(fù)制值,檢測(cè) Xposed 框架
    strcpy(v18, "de.robv.android.xposed.XposedBridge");
    // 復(fù)制值,檢測(cè) substrate 框架
    strcpy(v17, "com.saurik.substrate");
    for ( i = 0; i < ArrayLength; ++i )
    {
    ObjectArrayElement = _JNIEnv::GetObjectArrayElement(a1, v9, i);
    ObjectClass = _JNIEnv::GetObjectClass(a1, ObjectArrayElement);
    // 每個(gè)堆棧中的信息反射獲取類(lèi)名
    v1 = _JNIEnv::GetMethodID(a1, ObjectClass, "getClassName", "()Ljava/lang/String;");
    v2 = _JNIEnv::CallObjectMethod(a1, ObjectArrayElement, v1);
    StringUTFChars = (const char *)_JNIEnv::GetStringUTFChars(a1, v2, 0);
    n = _strlen_chk(v18, 0x24u);
    // 比對(duì)
    if ( !strncmp(StringUTFChars, v18, n) )
    {
        _android_log_print(6, "lilac", "%s", StringUTFChars);
        _android_log_print(6, "lilac", byte_389E);
    }
    v16 = _strlen_chk(v17, 0x15u);
    if ( !strncmp(StringUTFChars, v17, v16) )
    {
        _android_log_print(6, "lilac", "%s", StringUTFChars);
        _android_log_print(6, "lilac", byte_38AE);
    }
    }
    return _stack_chk_guard;
    

    }

上述代碼也很簡(jiǎn)單,獲取當(dāng)前的調(diào)用堆棧,并利用反射把每條堆棧信息的類(lèi)找到,比對(duì)類(lèi)名,是否使用Xposed框架和substrate框架,這里也沒(méi)有任何的操作。接下來(lái),我們直接去用unidbg去調(diào)用起來(lái)這個(gè)so。

模擬執(zhí)行so

參數(shù)獲取

首先,我們來(lái)看下入?yún)⒌臉?gòu)造:

String r1 = getHash(getApplicationContext().getPackageCodePath());

很明顯是應(yīng)用的一些信息,對(duì)于這種的系統(tǒng)級(jí)別的API,可以去官網(wǎng)查看,也可以通過(guò)Hook快速去獲取值,這里我們使用Frida去Hook應(yīng)用程序快速拿到值,畢竟這個(gè)不是重要的環(huán)節(jié)。

Frida的Hook代碼如下所示:

function main(){
    Java.perform(function(){
        var MainActivity = Java.use("com.example.dogpro.MainActivity");
        MainActivity.onCreate.overload("android.os.Bundle").implementation = function(var_0){

            console.log("info:",this.getApplicationContext().getPackageCodePath())

            var ret = this.onCreate.overload("android.os.Bundle").call(this,var_0);
    }


    })
}


setImmediate(main)

Hook后的結(jié)果如圖3所示:

Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
圖21-3 Hook的結(jié)果

getPackageCodePath()返回此上下文的主要 Android 包的完整路徑。 Android 包是一個(gè) ZIP
文件,其中包含應(yīng)用程序的主要代碼和資產(chǎn)。也就是我們看到的base.apk文件。

拿到入?yún)⒑缶涂梢蚤_(kāi)始構(gòu)造unidbg的模擬執(zhí)行代碼了。在很多場(chǎng)景下,為了快速獲取結(jié)果,甚至都不需要打開(kāi)IDA去分析又臭又長(zhǎng)的偽代碼,直接把so放到unidbg中去跑,減少對(duì)IDA的依賴(lài)。

如果單純的做算法的分析,毋庸置疑我們一定會(huì)使用到IDA。如果我們只是去獲取一個(gè)執(zhí)行的結(jié)果,我們使用unidbg去模擬就可以了。

unidbg 代碼初始化

unidbg的代碼初始化是把對(duì)應(yīng)的模擬器、內(nèi)存以及module等接口都配置好,這部分經(jīng)過(guò)網(wǎng)上案例大量的練習(xí),相信大家已經(jīng)可以熟能生巧了,這里再次給大家展示一下,代碼如下所示:

public class MainActivity extends AbstractJni{
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Memory memory;
    private final Module module;

    public MainActivity(){
        emulator = AndroidEmulatorBuilder
                // 創(chuàng)建32位的模擬器
                .for32Bit()
                // 建立模擬器
                .build();

        // 實(shí)現(xiàn)內(nèi)存接口
        memory = emulator.getMemory();
        // 設(shè)置解析的庫(kù)的SDK
        memory.setLibraryResolver(new AndroidResolver(23));

        // 創(chuàng)建虛擬機(jī)
        vm = emulator.createDalvikVM();
        // 日志開(kāi)關(guān)
        vm.setVerbose(true);
        // 實(shí)現(xiàn) JNI
        vm.setJni(this);
        // 加載so
        DalvikModule dalvikModule = vm.loadLibrary(
                new File("unidbg-android/src/test/java/com/r0ysue/Chap22/apkfile/lib/armeabi-v7a/libdogpro.so"), false);
        module = dalvikModule.getModule();
        vm.callJNI_OnLoad(emulator,module);
    }

    public static void main(String[] args) {
        MainActivity mainActivity = new MainActivity();
        mainActivity.getHash();
    }
}
目標(biāo)函數(shù)的調(diào)用

我們調(diào)用的就是so中的getHash函數(shù),它是一個(gè)non-static方法,需要一個(gè)實(shí)例來(lái)調(diào)用,讓我們先看看代碼是怎么寫(xiě)的:

private void getHash() {
    // 找到調(diào)用它的類(lèi),和哪個(gè)類(lèi)綁定就使用哪個(gè)類(lèi)
    DvmObject<?> dvmObject = vm.resolveClass("com/example/dogpro/MainActivity").newObject(null);
    // 上面找到的入?yún)?    String input = "/data/app/com.example.dogpro-pnF2J3-qBi8ei74vXTNXmQ==/base.apk";
    // 
    DvmObject<?> ret = dvmObject.callJniMethodObject(emulator, "getHash(Ljava/lang/String;)Ljava/lang/String;", input);
    System.out.println("result ==> "+ret.getValue());
}
補(bǔ)環(huán)境說(shuō)明

首先需要找到調(diào)用這個(gè)方法的類(lèi)是哪個(gè),和哪個(gè)類(lèi)綁定就使用哪個(gè)類(lèi)。因?yàn)榉椒ㄊ且粋€(gè)實(shí)例方法,我們通過(guò)newObject來(lái)實(shí)例化這個(gè)類(lèi)。調(diào)用是通過(guò)dvmObject來(lái)操作,對(duì)于JNI方法有如下幾種類(lèi)型,如圖4所示:

Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
圖4 callJnixxx的幾種類(lèi)型

具體的選擇需要看函數(shù)的返回值,樣本中的getHash函數(shù)返回的類(lèi)型是String,而String的本質(zhì)就是一個(gè)Object,所以使用callJniMethodObject來(lái)操縱。

callJniMethodObject中需要傳遞三個(gè)參數(shù),第一個(gè)是emulator;第二個(gè)是方法及簽名,這個(gè)可以通過(guò)Jadx-
gui反編譯的結(jié)果查看,如圖5所示:

Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
圖5 callJniMethodObject中的方法簽名

最后就是方法中參數(shù)的傳遞,它是一個(gè)可變長(zhǎng)度的參數(shù)列表。

至此,getHash的調(diào)用就構(gòu)造完成了,然后我們?nèi)ミ\(yùn)行代碼,看看是否可以正常的運(yùn)行。第一次運(yùn)行后,運(yùn)行結(jié)果主要報(bào)錯(cuò)信息如下所示:

java.lang.UnsupportedOperationException: java/util/zip/ZipFile-><init>(Ljava/lang/String;)V
	at com.github.unidbg.linux.android.dvm.AbstractJni.newObjectV(AbstractJni.java:791)
	at com.github.unidbg.linux.android.dvm.AbstractJni.newObjectV(AbstractJni.java:746)
    ...

額外說(shuō)明一點(diǎn),如果我們沒(méi)有去繼承AbstractJNI,會(huì)出現(xiàn)setJNI的錯(cuò)誤,這里已經(jīng)補(bǔ)全了,就不會(huì)出現(xiàn)了。這段報(bào)錯(cuò)具體是什么含義呢?大致就是要找java/util/zip/ZipFile這個(gè)類(lèi)的構(gòu)造方法,但是找不到,所以報(bào)了上述的錯(cuò)誤。找不到類(lèi)之后,后續(xù)就不知道改怎么往下執(zhí)行,最終拋出了異常。這種就是Java的一個(gè)環(huán)境問(wèn)題。

實(shí)戰(zhàn)補(bǔ)環(huán)境

那我們?cè)趺慈パa(bǔ)充這個(gè)環(huán)境呢?其實(shí)它已經(jīng)很智能了,框架都填好了,只需要我們稍作改動(dòng)即可。補(bǔ)環(huán)境,即它要什么,我們就給他什么,根據(jù)這個(gè)提示來(lái)就好。給我們拋出的異常就是一種提示。找到下述異常的所在位置:

// com.github.unidbg.linux.android.dvm.AbstractJni.newObjectV(AbstractJni.java:791)

@Override
public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    switch (signature) {
        case "java/io/ByteArrayInputStream-><init>([B)V": {
            ByteArray array = vaList.getObjectArg(0);
            assert array != null;
            return vm.resolveClass("java/io/ByteArrayInputStream").newObject(new ByteArrayInputStream(array.value));
        }
        ...
    }
}

這里僅僅展示了一個(gè)case,在這個(gè)方法中,有很多case,這是unidbg作者在設(shè)計(jì)的時(shí)候幫我們做好的,補(bǔ)好的這些具有很強(qiáng)的通用性。而沒(méi)補(bǔ)齊的是比較特殊的:可能是引用了三方的SDK中的函數(shù),也有可能是廠商自己的函數(shù),這就需要使用者自己去補(bǔ)充。補(bǔ)環(huán)境就是在這個(gè)方法中接著case繼續(xù)去寫(xiě)分支。但是這個(gè)是在unidbg的項(xiàng)目中,為了代碼的可移植性,建議大家寫(xiě)到自己的代碼中,因?yàn)橐呀?jīng)繼承了AbstraceJNI,只需要重寫(xiě)就可以了。對(duì)于上面的報(bào)錯(cuò),補(bǔ)的代碼如下所示:

@Override
public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipFile-><init>(Ljava/lang/String;)V")){
        return vm.resolveClass("java/util/zip/ZipFile").newObject(null);
    }
    return super.newObjectV(vm, dvmClass, signature, vaList);
}

但是大家思考一個(gè)問(wèn)題,這是一個(gè)構(gòu)造方法,并且報(bào)錯(cuò)異常中也提供了方法的簽名,它的入?yún)⑹且粋€(gè)String類(lèi)型的,沒(méi)有返回值,那我們只是簡(jiǎn)單的給他傳一個(gè)null對(duì)象肯定是不行的。先把他的入?yún)⒋蛴〕鰜?lái)看看:

@Override
public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipFile-><init>(Ljava/lang/String;)V")){
        String name = (String) vaList.getObjectArg(0).getValue();
        System.out.println("name => " + name);
        return vm.resolveClass("java/util/zip/ZipFile").newObject(null);
    }
    return super.newObjectV(vm, dvmClass, signature, vaList);
}

打印的結(jié)果如下所示:

name => /data/app/com.example.dogpro-pnF2J3-qBi8ei74vXTNXmQ==/base.apk

很明顯這里傳了一個(gè)APK文件,其主要作用就是解析獲取APK內(nèi)部的資源。那我們同樣去構(gòu)造一個(gè)這樣的數(shù)據(jù),把它作為對(duì)象讓unidbg去解析,補(bǔ)完后的結(jié)果如下所示:

@Override
public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipFile-><init>(Ljava/lang/String;)V")){
        String name = (String) vaList.getObjectArg(0).getValue();
        // System.out.println("name => " + name);
        // return vm.resolveClass("java/util/zip/ZipFile").newObject(null);
        try {
            ZipFile zipFile = new ZipFile(name);
            return vm.resolveClass("java/util/zip/ZipFile").newObject(zipFile);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    return super.newObjectV(vm, dvmClass, signature, vaList);
}

再次運(yùn)行代碼,又有了新的異常報(bào)錯(cuò),如下所示:

[16:39:44 871]  WARN [com.github.unidbg.linux.ARM32SyscallHandler] (ARM32SyscallHandler:532) - handleInterrupt intno=2, NR=-1073744324, svcNumber=0x11f, PC=unidbg@0xfffe0284, LR=RX@0x400016e3[libdogpro.so]0x16e3, syscall=null
java.lang.NullPointerException
	at com.github.unidbg.linux.android.dvm.DalvikVM$32.handle(DalvikVM.java:540)
	at com.github.unidbg.linux.ARM32SyscallHandler.hook(ARM32SyscallHandler.java:131)
	at com.github.unidbg.arm.backend.UnicornBackend$11.hook(UnicornBackend.java:345)
	at unicorn.Unicorn$NewHook.onInterrupt(Unicorn.java:128)
	at unicorn.Unicorn.emu_start(Native Method)
	at com.github.unidbg.arm.backend.UnicornBackend.emu_start(UnicornBackend.java:376)
	at com.github.unidbg.AbstractEmulator.emulate(AbstractEmulator.java:380)
    ...
[16:39:44 873]  WARN [com.github.unidbg.AbstractEmulator] (AbstractEmulator:420) - emulate RX@0x40001281[libdogpro.so]0x1281 exception sp=unidbg@0xbffff610, msg=java.lang.NullPointerException, offset=7ms
java.nio.file.NoSuchFileException: /data/app/com.example.dogpro-pnF2J3-qBi8ei74vXTNXmQ==/base.apk
	at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
	at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)

我們來(lái)看最下面的模擬器拋出的異常,即NoSuchFileException,是java中最常見(jiàn)的異常,沒(méi)有找到這個(gè)文件的異常。大家注意:我們當(dāng)前使用的是unidbg,而不是一個(gè)手機(jī)的真實(shí)環(huán)境,所以打印出來(lái)的name,即文件的路徑我們根本沒(méi)有,那怎么辦呢?傳一個(gè)本地的APK到模擬器中,最終的代碼如下所示:

@Override
public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipFile-><init>(Ljava/lang/String;)V")){
        String name = (String) vaList.getObjectArg(0).getValue();
        // System.out.println("name => " + name);
        // return vm.resolveClass("java/util/zip/ZipFile").newObject(null);
        try {
            if(name.equals("/data/app/com.example.dogpro-pnF2J3-qBi8ei74vXTNXmQ==/base.apk")){
                ZipFile zipFile = new ZipFile("unidbg-android/src/test/java/com/r0ysue/unidbgBook/Chap22/dogpro.apk");
                // ZipFile zipFile = new ZipFile(name);
                return vm.resolveClass("java/util/zip/ZipFile").newObject(zipFile);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    return super.newObjectV(vm, dvmClass, signature, vaList);
}

這里直接根據(jù)簽名信息返回了一個(gè)ZipFile的對(duì)象,然后我們把unidbg中補(bǔ)好的方法return回去,即執(zhí)行unidbg中補(bǔ)好的環(huán)境。別的問(wèn)題暫時(shí)沒(méi)有出現(xiàn),我們先不做處理。補(bǔ)充完后再次運(yùn)行代碼,報(bào)錯(cuò)如下所示:

java.lang.UnsupportedOperationException: java/util/zip/ZipFile->entries()Ljava/util/Enumeration;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:416)
	at com.r0ysue.unidbgBook.Chap22.MainActivity.callObjectMethodV(MainActivity.java:124)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)
    ...

報(bào)錯(cuò)的異常顯示,缺少了ZipFie的entries方法,這個(gè)方法是空參,返回值類(lèi)型是Enumeration對(duì)象。我們繼續(xù)使用上面的方法去補(bǔ)環(huán)境,補(bǔ)完后的代碼如下所示:

@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipFile->entries()Ljava/util/Enumeration;")){
        // 拿到操作的對(duì)象
        ZipFile zipFile = (ZipFile) dvmObject.getValue();
        // 通過(guò)對(duì)象來(lái)調(diào)用方法
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        return vm.resolveClass("java/util/Enumeration").newOnject(entries);
    }
    return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

注意這里要補(bǔ)的環(huán)境是在callObjectMethodV方法中,根據(jù)名稱(chēng)我們也能知道,它是在調(diào)用對(duì)象中的方法,參數(shù)dvmObject就是對(duì)象,而這里是調(diào)用ZipFile形成的對(duì)象中的entries方法,ZipFile對(duì)象是在上一個(gè)方法中做的實(shí)例化,并傳入了待解析的APK文件。我們要正真的獲取這個(gè)對(duì)象就需要通過(guò)getValue()方法來(lái)獲取。然后通過(guò)這個(gè)對(duì)象來(lái)調(diào)用entries方法。根據(jù)簽名可以知道要返回的類(lèi)型是Enumeration,直接通過(guò)前面的方法返回回去。繼續(xù)運(yùn)行代碼,看看用這種方式能不能起作用:

[17:09:25 902]  WARN [com.github.unidbg.linux.ARM32SyscallHandler] (ARM32SyscallHandler:532) - handleInterrupt intno=2, NR=-1073744324, svcNumber=0x122, PC=unidbg@0xfffe02b4, LR=RX@0x40001253[libdogpro.so]0x1253, syscall=null
java.lang.ClassCastException: class com.github.unidbg.linux.android.dvm.DvmObject cannot be cast to class com.github.unidbg.linux.android.dvm.Enumeration (com.github.unidbg.linux.android.dvm.DvmObject and com.github.unidbg.linux.android.dvm.Enumeration are in unnamed module of loader 'app')
	at com.github.unidbg.linux.android.dvm.AbstractJni.callBooleanMethodV(AbstractJni.java:609)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callBooleanMethodV(AbstractJni.java:602)

最開(kāi)始顯示了報(bào)錯(cuò)的主要信息,即xxx.DvmObject cannot be cast to
xxx.Enumeration,它們的關(guān)系不能通過(guò)強(qiáng)轉(zhuǎn)來(lái)實(shí)現(xiàn)。一般出現(xiàn)這種疑難雜癥,我們的首要手段是到unidbg的框架中搜索,看看它有沒(méi)有相關(guān)的處邏輯,在AbstractJNI中,我們果真找到了它的實(shí)現(xiàn)邏輯:

@Override
public boolean callBooleanMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    switch (signature) {
        case "java/util/Enumeration->hasMoreElements()Z":
            return ((Enumeration) dvmObject).hasMoreElements();
    }
}

在AbstractJNI的同級(jí)目錄下,可以發(fā)現(xiàn)unidbg對(duì)它的實(shí)現(xiàn)

package com.github.unidbg.linux.android.dvm;

import java.util.Iterator;
import java.util.List;

public class Enumeration extends DvmObject<List<?>> {

    private final Iterator<? extends DvmObject<?>> iterator;

    public Enumeration(VM vm, List<? extends DvmObject<?>> value) {
        super(vm.resolveClass("java/util/Enumeration"), value);

        this.iterator = value == null ? null : value.iterator();
    }

    public boolean hasMoreElements() {
        return iterator != null && iterator.hasNext();
    }

    public DvmObject<?> nextElement() {
        return iterator.next();
    }

}

在Java的中同樣有Enumeration類(lèi)的實(shí)現(xiàn),為什么會(huì)這樣呢?這是因?yàn)閡nidbg對(duì)簡(jiǎn)單的數(shù)據(jù)類(lèi)型都做了封裝,并優(yōu)先使用。比如,我們要返回一個(gè)String的對(duì)象,一般是這樣來(lái)寫(xiě)的:

return new StringObject(vm,"");

而不是使用resolveClass的方式:

return vm.resolveClass("java/lang/String"),newOnject(");

這是為了后續(xù)的處理,unidbg是一個(gè)完善的系統(tǒng),每個(gè)環(huán)節(jié)都有相應(yīng)的承接,如果使用后者,那么后續(xù)的操作需要去做強(qiáng)轉(zhuǎn)就無(wú)法識(shí)別,從而強(qiáng)轉(zhuǎn)失敗。我們既然知道了unidbg中基本的數(shù)據(jù)類(lèi)型,就要使用它。

到了這步,就該往里面?zhèn)魅雲(yún)?shù)了,看下unidbg的Enumeration構(gòu)造方法:

public Enumeration(VM vm, List<? extends DvmObject<?>> value) {
    super(vm.resolveClass("java/util/Enumeration"), value);
    this.iterator = value == null ? null : value.iterator();
}

需要傳入的是一個(gè)List類(lèi)型的對(duì)象,所以我們?nèi)パa(bǔ)環(huán)境的時(shí)候同樣也需要給他一個(gè)List對(duì)象,最終的代碼如下所示:

@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipFile->entries()Ljava/util/Enumeration;")){
        ZipFile zipFile = (ZipFile) dvmObject.getValue();
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        // return vm.resolveClass("java/util/Enumeration").newObject(entries);
        DvmClass ZipEntryClass = vm.resolveClass("java/util/zip/ZipEntry");
        List<DvmObject<?>> objs = new ArrayList<>();
        while (entries.hasMoreElements()){
            ZipEntry zipEntry = entries.nextElement();
            objs.add(ZipEntryClass.newObject(zipEntry));
        }
        return new com.github.unidbg.linux.android.dvm.Enumeration(vm,objs);
    }

同理,我們繼續(xù)往下補(bǔ),先運(yùn)行上述的代碼,拋出的異常如下所示:

java.lang.UnsupportedOperationException: java/util/zip/ZipEntry->getName()Ljava/lang/String;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:416)
	at com.r0ysue.unidbgBook.Chap22.MainActivity.callObjectMethodV(MainActivity.java:128)

同樣是在調(diào)用對(duì)象的方法,我們需要先獲取對(duì)象,然后再用對(duì)象調(diào)用對(duì)應(yīng)的方法,它需要的返回值是一個(gè)Sting類(lèi)型,即通過(guò)StrongObject返回,代碼如下所示:

@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipEntry->getName()Ljava/lang/String;")){
        ZipEntry zipEntry = (ZipEntry) dvmObject.getValue();
        String name = zipEntry.getName();
        return new  StringObject(vm,name);
    }
    return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

繼續(xù)運(yùn)行代碼,報(bào)錯(cuò)如下所示:

java.lang.UnsupportedOperationException: java/lang/String->endsWith(Ljava/lang/String;)Z
	at com.github.unidbg.linux.android.dvm.AbstractJni.callBooleanMethodV(AbstractJni.java:624)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callBooleanMethodV(AbstractJni.java:602)

這個(gè)報(bào)錯(cuò)出現(xiàn)在callBooleanMethodV方法中,代碼如下所示:

@Override
public boolean callBooleanMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/lang/String->endsWith(Ljava/lang/String;)Z")){
        String value = (String) dvmObject.getValue();
        String suffix = (String) vaList.getObjectArg(0).getValue();
        return value.endsWith(suffix);
    }
    return super.callBooleanMethodV(vm, dvmObject, signature, vaList);
}

同樣,我們需要先拿到對(duì)象,而且endsWith函數(shù)中有參數(shù)的傳遞,我們需要把參數(shù)也構(gòu)造出來(lái),vaList是一個(gè)可變的參數(shù)列表,拿第一個(gè)參數(shù)即可。繼續(xù)運(yùn)行代碼,報(bào)錯(cuò)異常如下所示:

java.lang.UnsupportedOperationException: java/util/zip/ZipFile->getInputStream(Ljava/util/zip/ZipEntry;)Ljava/io/InputStream;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:416)
	at com.r0ysue.unidbgBook.Chap22.MainActivity.callObjectMethodV(MainActivity.java:128)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)

這個(gè)也是在callObjectMethodV方法中,代碼如下所示:

@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/util/zip/ZipFile->getInputStream(Ljava/util/zip/ZipEntry;)Ljava/io/InputStream;")){
        ZipFile zipFile = (ZipFile) dvmObject.getValue();
        ZipEntry zipEntry = (ZipEntry) vaList.getObjectArg(0).getValue();
        try {
            InputStream inputStream = zipFile.getInputStream(zipEntry);
            return vm.resolveClass("java/io/InputStream").newObject(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

由于涉及到了IO的操作,需要包裹到try…catch…中,繼續(xù)運(yùn)行代碼,報(bào)錯(cuò)如下所示:

java.lang.UnsupportedOperationException: java/io/InputStream->read([B)I
	at com.github.unidbg.linux.android.dvm.AbstractJni.callIntMethodV(AbstractJni.java:562)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callIntMethodV(AbstractJni.java:528)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callIntMethodV(DvmMethod.java:109)
	at com.github.unidbg.linux.android.dvm.DalvikVM$47.handle(DalvikVM.java:821)

報(bào)錯(cuò)發(fā)生在callIntMethodV中,需要補(bǔ)的是InputStream中的read方法,根據(jù)參數(shù)和返回值,補(bǔ)充的代碼如下所示:

@Override
public int callIntMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/io/InputStream->read([B)I")){
        InputStream inputStream = (InputStream) dvmObject.getValue();
        byte[] bytes = (byte[]) vaList.getObjectArg(0).getValue();
        try {
            int read = inputStream.read(bytes);
            return read;
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
    }
    return super.callIntMethodV(vm, dvmObject, signature, vaList);
}

繼續(xù)運(yùn)行代碼,報(bào)錯(cuò)信息如下所示:

java.lang.UnsupportedOperationException: java/security/MessageDigest->update([B)V
	at com.github.unidbg.linux.android.dvm.AbstractJni.callVoidMethodV(AbstractJni.java:995)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callVoidMethodV(AbstractJni.java:978)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callVoidMethodV(DvmMethod.java:228)
	at com.github.unidbg.linux.android.dvm.DalvikVM$59.handle(DalvikVM.java:1045)

調(diào)用了Java SDK中的MessageDigest類(lèi),我們繼續(xù)補(bǔ),代碼如下所示:

@Override
public void callVoidMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/security/MessageDigest->update([B)V")){
        MessageDigest md = (MessageDigest) dvmObject.getValue();
        byte[] bytes = (byte[]) vaList.getObjectArg(0).getValue();
        md.update(bytes);
        return;
    }
    super.callVoidMethodV(vm, dvmObject, signature, vaList);
}

繼續(xù)運(yùn)行代碼,報(bào)錯(cuò)如下所示:

java.lang.UnsupportedOperationException: java/security/MessageDigest->digest()[B
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:416)
	at com.r0ysue.unidbgBook.Chap22.MainActivity.callObjectMethodV(MainActivity.java:128)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)

還缺少了digest方法,我們繼續(xù)來(lái)補(bǔ)齊,代碼如下所示:

@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
    if (signature.equals("java/security/MessageDigest->digest()[B")){
        MessageDigest md = (MessageDigest) dvmObject.getValue();
        byte[] digest = md.digest();
        return new ByteArray(vm, digest);
    }
    return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

再次運(yùn)行代碼,返回的結(jié)果就出來(lái)了,于此同時(shí),給大家打開(kāi)了setVarbose開(kāi)關(guān),把JNI的執(zhí)行流也輸出了,結(jié)果如下所示:

JNIEnv->CallObjectMethodV(java.util.Enumeration@c730b35, nextElement() => java.util.zip.ZipEntry@3f6f6701) was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV(java.util.zip.ZipEntry@3f6f6701, getName() => "res/drawable/design_ic_visibility.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV("res/drawable/design_ic_visibility.xml", toLowerCase() => "res/drawable/design_ic_visibility.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->GetStringUtfChars("res/drawable/design_ic_visibility.xml") was called from RX@0x40001749[libdogpro.so]0x1749
JNIEnv->CallBooleanMethodV("res/drawable/design_ic_visibility.xml", endsWith("dog.png") => false) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallBooleanMethodV(java.util.Enumeration@c730b35, hasMoreElements() => true) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallObjectMethodV(java.util.Enumeration@c730b35, nextElement() => java.util.zip.ZipEntry@1ed6388a) was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV(java.util.zip.ZipEntry@1ed6388a, getName() => "res/drawable/design_ic_visibility_off.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV("res/drawable/design_ic_visibility_off.xml", toLowerCase() => "res/drawable/design_ic_visibility_off.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->GetStringUtfChars("res/drawable/design_ic_visibility_off.xml") was called from RX@0x40001749[libdogpro.so]0x1749
JNIEnv->CallBooleanMethodV("res/drawable/design_ic_visibility_off.xml", endsWith("dog.png") => false) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallBooleanMethodV(java.util.Enumeration@c730b35, hasMoreElements() => true) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallObjectMethodV(java.util.Enumeration@c730b35, nextElement() => java.util.zip.ZipEntry@4f80542f) was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV(java.util.zip.ZipEntry@4f80542f, getName() => "res/drawable/design_password_eye.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV("res/drawable/design_password_eye.xml", toLowerCase() => "res/drawable/design_password_eye.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->GetStringUtfChars("res/drawable/design_password_eye.xml") was called from RX@0x40001749[libdogpro.so]0x1749
JNIEnv->CallBooleanMethodV("res/drawable/design_password_eye.xml", endsWith("dog.png") => false) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallBooleanMethodV(java.util.Enumeration@c730b35, hasMoreElements() => true) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallObjectMethodV(java.util.Enumeration@c730b35, nextElement() => java.util.zip.ZipEntry@130c12b7) was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV(java.util.zip.ZipEntry@130c12b7, getName() => "res/drawable/design_snackbar_background.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV("res/drawable/design_snackbar_background.xml", toLowerCase() => "res/drawable/design_snackbar_background.xml") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->GetStringUtfChars("res/drawable/design_snackbar_background.xml") was called from RX@0x40001749[libdogpro.so]0x1749
JNIEnv->CallBooleanMethodV("res/drawable/design_snackbar_background.xml", endsWith("dog.png") => false) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallBooleanMethodV(java.util.Enumeration@c730b35, hasMoreElements() => true) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->CallObjectMethodV(java.util.Enumeration@c730b35, nextElement() => java.util.zip.ZipEntry@5d534f5d) was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV(java.util.zip.ZipEntry@5d534f5d, getName() => "res/drawable/dog.png") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->CallObjectMethodV("res/drawable/dog.png", toLowerCase() => "res/drawable/dog.png") was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->GetStringUtfChars("res/drawable/dog.png") was called from RX@0x40001749[libdogpro.so]0x1749
JNIEnv->CallBooleanMethodV("res/drawable/dog.png", endsWith("dog.png") => true) was called from RX@0x40001253[libdogpro.so]0x1253
JNIEnv->GetMethodID(java/util/zip/ZipFile.getInputStream(Ljava/util/zip/ZipEntry;)Ljava/io/InputStream;) => 0xb225c4d4 was called from RX@0x40001195[libdogpro.so]0x1195
JNIEnv->CallObjectMethodV(java.util.zip.ZipFile@557caf28, getInputStream(java.util.zip.ZipEntry@5d534f5d) => java.io.InputStream@a38c7fe) was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->GetMethodID(java/io/InputStream.read([B)I) => 0x7b2c3fda was called from RX@0x40001195[libdogpro.so]0x1195
JNIEnv->NewByteArray(256) was called from RX@0x40001769[libdogpro.so]0x1769
JNIEnv->FindClass(java/security/MessageDigest) was called from RX@0x40001127[libdogpro.so]0x1127
JNIEnv->GetStaticMethodID(java/security/MessageDigest.getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;) => 0x5c20796 was called from RX@0x40001799[libdogpro.so]0x1799
JNIEnv->NewStringUTF("MD5") was called from RX@0x40001165[libdogpro.so]0x1165
JNIEnv->CallStaticObjectMethodV(class java/security/MessageDigest, getInstance("MD5") => java.security.MessageDigest@25641d39) was called from RX@0x400017eb[libdogpro.so]0x17eb
JNIEnv->CallIntMethodV(java.io.InputStream@a38c7fe, read([B@7b36aa0c) => 0x100) was called from RX@0x4000185f[libdogpro.so]0x185f
JNIEnv->GetMethodID(java/security/MessageDigest.update([B)V) => 0x7d1a6599 was called from RX@0x40001195[libdogpro.so]0x1195
JNIEnv->CallVoidMethodV(java.security.MessageDigest@25641d39, update([B@7b36aa0c)) was called from RX@0x400011e7[libdogpro.so]0x11e7
JNIEnv->GetMethodID(java/security/MessageDigest.digest()[B) => 0x6ccd1d46 was called from RX@0x40001195[libdogpro.so]0x1195
JNIEnv->CallObjectMethodV(java.security.MessageDigest@25641d39, digest() => [B@5824a83d) was called from RX@0x400016e3[libdogpro.so]0x16e3
JNIEnv->GetArrayLength([B@5824a83d => 16) was called from RX@0x400018c7[libdogpro.so]0x18c7
JNIEnv->NewStringUTF("D3E550889725A6A7C5E834ECCDB4B73E") was called from RX@0x40001165[libdogpro.so]0x1165
result ==> D3E550889725A6A7C5E834ECCDB4B73E

明顯的可以看到,JNI的執(zhí)行流就是我們剛才補(bǔ)充環(huán)境的順序,當(dāng)然有一些是unidbg幫我們補(bǔ)好的。

跟著筆者的思路一路下來(lái)終于把結(jié)果運(yùn)行了出來(lái),過(guò)程中不知補(bǔ)了多少函數(shù)。但是獲取最終結(jié)果的那一剎那,前面做的所有的努力都是值得的。有意思的是,我們并不知道這其中會(huì)有多少函數(shù),也不知道我們會(huì)在哪一個(gè)節(jié)點(diǎn)放棄,這可能就是unidbg的魅力吧。就像人生一樣,我們并不知道是否會(huì)有一個(gè)結(jié)果,在每一個(gè)時(shí)間節(jié)點(diǎn)都在努力,但是不知道這樣的堅(jiān)持是否會(huì)有結(jié)果,期待每一個(gè)讀者都會(huì)有一個(gè)完美的結(jié)局。

最后

對(duì)于從來(lái)沒(méi)有接觸過(guò)網(wǎng)絡(luò)安全的同學(xué),我們幫你準(zhǔn)備了詳細(xì)的學(xué)習(xí)成長(zhǎng)路線圖??梢哉f(shuō)是最科學(xué)最系統(tǒng)的學(xué)習(xí)路線,大家跟著這個(gè)大的方向?qū)W習(xí)準(zhǔn)沒(méi)問(wèn)題。
Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
同時(shí)每個(gè)成長(zhǎng)路線對(duì)應(yīng)的板塊都有配套的視頻提供:
Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
當(dāng)然除了有配套的視頻,同時(shí)也為大家整理了各種文檔和書(shū)籍資料&工具,并且已經(jīng)幫大家分好類(lèi)了。
Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)
因篇幅有限,僅展示部分資料,有需要的小伙伴,可以【掃下方二維碼】免費(fèi)領(lǐng)取:
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-449801.html

到了這里,關(guān)于Unidbg補(bǔ)環(huán)境實(shí)戰(zhàn)第一篇:補(bǔ)環(huán)境入門(mén)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue入門(mén)簡(jiǎn)介【第一篇】

    Vue入門(mén)簡(jiǎn)介【第一篇】

    ? ? ? ? ??? 1.1? 什么是Vue ? ? ?vue是一個(gè)構(gòu)建用戶(hù)界面UI的 漸進(jìn)式j(luò)avascript框架 ,漸進(jìn)式的框架是指可以一步一步的由淺入深的去使用該框架。 ? ? ? vue官網(wǎng): https://cn.vuejs.org/ ? ? ? ? ??? 1.2 Vue的 優(yōu)點(diǎn)? ??? 1、體積小 ?? ?壓縮后33k左右,體積小意味著下載速度很快

    2024年02月03日
    瀏覽(25)
  • 數(shù)據(jù)結(jié)構(gòu)入門(mén)篇:第一篇

    數(shù)據(jù)結(jié)構(gòu)入門(mén)篇:第一篇

    ??首先,為什么要學(xué)數(shù)據(jù)結(jié)構(gòu)? 數(shù)據(jù)結(jié)構(gòu)的 概念 :在內(nèi)存中對(duì)數(shù)據(jù)進(jìn)行管理; 數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí)能讓我們?cè)谔幚泶罅繑?shù)據(jù)時(shí)提高處理效率,即讓我們?cè)诓煌膱?chǎng)景下更快的處理大量數(shù)據(jù); ??算法和數(shù)據(jù)結(jié)構(gòu)有什么關(guān)系? 算法 就是處理數(shù)據(jù)的一種方法; 數(shù)據(jù)結(jié)構(gòu)是為算法服

    2023年04月18日
    瀏覽(26)
  • 【Cesium 編程第一篇】概述、環(huán)境搭建、界面介紹

    【Cesium 編程第一篇】概述、環(huán)境搭建、界面介紹

    年前年后一直在面試,發(fā)現(xiàn)一個(gè)奇怪的現(xiàn)象:很多互聯(lián)網(wǎng)公司經(jīng)受住三年的疫情沖擊,反而在疫情放開(kāi)的那一刻撐不住了,很多大廠都在批量的裁員:美國(guó)硅谷、北京字節(jié)、迪士尼中國(guó)等等。在北京的朋友也是年后到現(xiàn)在一直沒(méi)有找到合適的工作,當(dāng)然不是他技術(shù)不行找不到

    2024年02月08日
    瀏覽(89)
  • 【FPGA入門(mén)】第一篇、Verilog基本語(yǔ)法常識(shí)

    【FPGA入門(mén)】第一篇、Verilog基本語(yǔ)法常識(shí)

    目錄 第一部分、不同的變量類(lèi)型 1、wire和reg的區(qū)別 ?2、如何對(duì)變量進(jìn)行賦值呢? 3、什么是阻塞?什么是非阻塞? 第二部分、變量位寬的定義 1、各種系統(tǒng)默認(rèn)情況 2、變量位寬聲明方式 3、表明位寬的情況下,賦值方式 4、兩個(gè)模塊之間例化,不定義變量直接用的方式 5、常

    2024年02月04日
    瀏覽(26)
  • Qt +VTK+Cmake 編譯和環(huán)境配置(第一篇 采坑)

    Qt +VTK+Cmake 編譯和環(huán)境配置(第一篇 采坑)

    VTK下載地址:https://vtk.org/download/ cmake下載地址:https://cmake.org/download/ 版本對(duì)應(yīng)方面,如果你的項(xiàng)目對(duì)版本沒(méi)有要求,就不用在意。我就是自己隨機(jī)搭建的,VTK選擇最新版本吧,如果后面其他的庫(kù)不支持高版本 ,我在更好低版本的。這里只是介紹一下編譯過(guò)程。 ?這個(gè)最新版

    2024年02月10日
    瀏覽(20)
  • C#從入門(mén)到精通之第一篇: C#概述與入門(mén)

    C#從入門(mén)到精通之第一篇: C#概述與入門(mén)

    1.1 C#概述 C#語(yǔ)言及特點(diǎn) C#是微軟公司發(fā)布的一種面向?qū)ο蟮?、運(yùn)行于.NET Framework和 .Net Core(完全開(kāi)源,跨平臺(tái)能夠在Windows/Linux上運(yùn)行)之上的高級(jí)程序設(shè)計(jì)語(yǔ)言。 C#是一種安全的、穩(wěn)定的、簡(jiǎn)單的、優(yōu)雅的,由C和C++衍生出來(lái)的面向?qū)ο蟮木幊陶Z(yǔ)言。它在繼承C和C++強(qiáng)大功能的

    2024年02月04日
    瀏覽(37)
  • 【C語(yǔ)言必知必會(huì) | 第一篇】C語(yǔ)言入門(mén),這一篇就夠了

    【C語(yǔ)言必知必會(huì) | 第一篇】C語(yǔ)言入門(mén),這一篇就夠了

    引言 C語(yǔ)言是一門(mén)面向過(guò)程的、抽象化的通用程序設(shè)計(jì)語(yǔ)言,廣泛應(yīng)用于底層開(kāi)發(fā)。它在編程語(yǔ)言中具有舉足輕重的地位。 此文為【C語(yǔ)言必知必會(huì)】系列第一篇,帶你初步了解C語(yǔ)言,為之后的學(xué)習(xí)打下基礎(chǔ) C語(yǔ)言起源于美國(guó)貝爾實(shí)驗(yàn)室的貝爾實(shí)驗(yàn)室,由丹尼斯·里奇和肯尼斯

    2024年02月08日
    瀏覽(18)
  • Hadoop生態(tài)圈實(shí)戰(zhàn)系列:第一篇 Hadoop 集群安裝及使用詳解

    作者:禪與計(jì)算機(jī)程序設(shè)計(jì)藝術(shù) Apache Hadoop 是一款開(kāi)源的、分布式文件系統(tǒng)和計(jì)算平臺(tái)。它由 Apache 基金會(huì)開(kāi)發(fā),并于 2011 年成為 Apache 頂級(jí)項(xiàng)目之一。Hadoop 的主要特性包括: 分布式存儲(chǔ): Hadoop 允許將數(shù)據(jù)存儲(chǔ)在多個(gè)服務(wù)器上,在同一個(gè)集群中,并提供高容錯(cuò)性和可靠性。

    2024年02月08日
    瀏覽(22)
  • 【Python指南 | 第一篇】Python環(huán)境配置及pip安裝教程

    【Python指南 | 第一篇】Python環(huán)境配置及pip安裝教程

    在學(xué)習(xí)Python前需搭建Python環(huán)境,同時(shí)在部分情況下需使用pip,本文為Python指南第一篇,給出實(shí)操教程。 官網(wǎng): 選擇如下版本: 下載到: 接著將 添加到環(huán)境變量中的PATH中: cmd輸入Python,出現(xiàn)如下回顯說(shuō)明環(huán)境搭建成功: 使用vscode運(yùn)行python文件前,需安裝python拓展,及選擇

    2024年02月03日
    瀏覽(33)
  • Docker從入門(mén)到上天系列第一篇:Docker開(kāi)篇介紹

    Docker從入門(mén)到上天系列第一篇:Docker開(kāi)篇介紹

    ???? 歡迎加入我們的學(xué)習(xí)交流群呀! ??1:這是 孫哥suns 給大家的福利! ??2:我們 免費(fèi)分享Netty、Dubbo、k8s、Mybatis、Spring、Security、Docker、Grpc、消息中間件、Rpc、SpringCloud等等很多應(yīng)用和源碼級(jí)別高質(zhì)量視頻和筆記資料 ,你想學(xué)的我們這里都有! ????3:QQ群: 5837

    2024年02月21日
    瀏覽(21)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包