Android應(yīng)用混淆So庫(kù)中的方法名

前言

在Android應(yīng)用中,出于對(duì)安全性的考慮,開發(fā)者會(huì)把一些重要的邏輯放到native層,即so庫(kù)中。但是so庫(kù)也并非絕對(duì)的安全,在強(qiáng)大的IDA反編譯下,so庫(kù)中的邏輯也將無所遁形。今天,我們要說的就是混淆so庫(kù)中的方法名。

正文

我們先來看下為什么要這么做。我們新建一個(gè)Android項(xiàng)目,添加NDK支持,默認(rèn)項(xiàng)目中會(huì)有一個(gè)方法如下

external fun stringFromJNI(): String
companion object {
    // Used to load the 'native-lib' library on application startup.
    init {
        System.loadLibrary("native-lib")
    }
}

然后我們編譯運(yùn)行,在app/build/intermediates/cmake/debug/obj/armeabi/libnative-lib.so目錄下找到我們編譯出來的so庫(kù),在IDA中打開,我們可以很輕易的找到這個(gè)方法對(duì)應(yīng)的地方

image.png

為什么會(huì)這樣的?因?yàn)槲覀冊(cè)趯?code>JNI的時(shí)候,采用javah命令生成的頭文件,里面的方法名默認(rèn)就是java_com_xxxx這種形式。所以我們現(xiàn)在要做的就是改變這種映射關(guān)系。

當(dāng)虛擬機(jī)加載這個(gè)這個(gè)庫(kù)的時(shí)候,從java層進(jìn)入本地層首先會(huì)執(zhí)行JNI_Onload這個(gè)函數(shù),java層的方法就是在這個(gè)方法中注冊(cè)的,使用的方法為registerNativeMethods,我們?cè)谶@一步將注冊(cè)我們自定義的方法,這樣方法名就可以由我們自己來定義。接下來看代碼實(shí)現(xiàn)。

  • 重寫JNI_Onload方法
extern "C"
jint JNI_OnLoad(JavaVM* vm,void* reserved){
    JNIEnv* env;
    if (vm->GetEnv((void**)(&env), JNI_VERSION_1_6) != JNI_OK)
    {
        return -1;
    }
    //這一步,注冊(cè)我們的方法
    if (!registerNatives(env)) {
        return -1;
    }
    return JNI_VERSION_1_6;
}
  • 接下來看registerNatives方法的實(shí)現(xiàn)
static JNINativeMethod gMethods[] = {
        //第一個(gè)參數(shù)為Java層的方法名
        //第二個(gè)參數(shù)為方法的簽名,括號(hào)內(nèi)為參數(shù)類型,后面為返回類型
        //第三個(gè)參數(shù)即為我們需要重新注冊(cè)的方法名
        { "stringFromJNI", "()Ljava/lang/String;", (void*)getStr},
};

extern "C"
int registerNativeMethods(JNIEnv* env, const char* className,
                          JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

extern "C"
int registerNatives(JNIEnv* env)
{
    if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
                               sizeof(gMethods) / sizeof(gMethods[0])))
        return JNI_FALSE;

    return JNI_TRUE;
}

到這里我們成功的替換了注冊(cè)的方法,重新用IDA打開so庫(kù),發(fā)現(xiàn)我們這次找不到形如java_com_xxxx的方法了最后,還有一步,我們還得實(shí)現(xiàn)替換后的方法

extern "C"
//這里指定該代碼所在的段,編譯的時(shí)候就會(huì)把這個(gè)函數(shù)編譯到自定義的名叫”.mytext“的section里面
//由于我們?cè)趈ava層沒有定義這個(gè)函數(shù)因此要寫到一個(gè)自定義的section里面。
__attribute__((section (".mytext")))  JNICALL jstring getStr
        (JNIEnv *env, jobject obj)
{
    return (env)->NewStringUTF("abc");
}

至此,我們就完成了所有混淆方法的操作。

后記

這只是一步基礎(chǔ)的安全操作,也很容破解。比如通過IDA動(dòng)態(tài)調(diào)試找到RegisterNatives方法,就能直接找到所對(duì)應(yīng)的方法,也能通過直接找額外的段來找到這個(gè)方法,但是這些就不在本文詳細(xì)說明了,有興趣的同學(xué)可以自己去嘗試下。

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

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

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