Android 一二三代殼加固原理分析

簡(jiǎn)介

  • 所有的加固代碼 都需要通過(guò)Classloader加載然后才可以執(zhí)行

classloader介紹

  • 雙親委派機(jī)制

    雙親委派模式的工作原理的是;如果一個(gè)類加載器收到了類加載請(qǐng)求擦囊,它并不會(huì)自己先去加載麻养,而是把這個(gè)請(qǐng)求委托給父類的加載器去執(zhí)行
    如果父類加載器還存在其父類加載器,則進(jìn)一步向上委托侦高,依次遞歸械馆,請(qǐng)求最終將到達(dá)頂層的啟動(dòng)類加載器
    如果父類加載器可以完成類加載任務(wù)胖眷,就成功返回,倘若父類加載器無(wú)法完成此加載任務(wù)霹崎,子加載器才會(huì)嘗試自己去加載珊搀,這就是雙親委派模式
    即每個(gè)兒子都不愿意干活,每次有活就丟給父親去干尾菇,直到父親說(shuō)這件事我也干不了時(shí)境析,兒子自己想辦法去完成,這個(gè)就是雙親委派派诬。

  • Android中的classloader

    ClassLoader為抽象類劳淆;
    BootClassLoader預(yù)加載常用類,單例模式千埃。
    BaseDexClassLoader是PathClassLoader憔儿、DexClassLoader、InMemoryDexClassLoader的父類放可,類加載的主要邏輯都是在BaseDexClassLoader完成的谒臼。
    SecureClassLoader繼承了抽象類ClassLoader,拓展了ClassLoader類加入了權(quán)限方面的功能耀里,加強(qiáng)了安全性蜈缤,其子類URLClassLoader是用URL路徑從jar文件中加載類和資源。
    其中重點(diǎn)關(guān)注的是PathClassLoader和DexClassLoader冯挎。
    PathClassLoader是Android默認(rèn)使用的類加載器底哥,一個(gè)apk中的Activity等類便是在其中加載。
    DexClassLoader可以加載任意目錄下的dex/jar/apk/zip文件房官,比PathClassLoader更靈活趾徽,是實(shí)現(xiàn)插件化、熱修復(fù)以及dex加殼的重點(diǎn)翰守。
    Android8.0新引入InMemoryDexClassLoader孵奶,從名字便可看出是用于直接從內(nèi)存中加載dex。

596742716226444.png

APP 的啟動(dòng)流程

534413116246610.png

APP類加載過(guò)程

  • BootClassLoader加載系統(tǒng)核心庫(kù)
  • PathClassLoader加載APP自身dex
  • 進(jìn)入APP自身組件開始執(zhí)行蜡峰,調(diào)用聲明Application的attachBaseContext了袁,onCreate
    • AppThread中有LoadedApk對(duì)象。
    • AppThread handledBindApplication(應(yīng)該是AMS 回調(diào)的ApplicationThread)中湿颅,第一次進(jìn)入到App自身的代碼中去载绿。
    • Application attach -> oncreate最先被執(zhí)行,如果加殼的話油航,此時(shí)的classloader只有殼的代碼 沒有自身代碼
    • 如果不處理classloader的話崭庸,只有殼代碼,是無(wú)法啟動(dòng)注冊(cè)的Activity Service等的谊囚。
      *<mark> 所以殼代碼需要在這里加載真正的代碼</mark>

組件生命周期的處理

DexClassLoader加載的類是沒有組件生命周期的怕享,也就是說(shuō)即使DexClassLoader通過(guò)對(duì)APK的動(dòng)態(tài)加載完成了對(duì)組件類的加載,當(dāng)系統(tǒng)啟動(dòng)該組件時(shí)秒啦,依然會(huì)出現(xiàn)加載類失敗的異常熬粗。
需要替換系統(tǒng)組件的classloader才可以。加固廠商必然饒不過(guò)去
兩種解決方案:
1余境、替換系統(tǒng)組件類加載器為我們的DexClassLoader驻呐,同時(shí)設(shè)置DexClassLoader的parent為系統(tǒng)組件類加載器;

//classloader 已經(jīng)加載了 自身代碼 并且parent是原始的classloader
public void replaceClassloader(ClassLoader classloader){
        try {
            Class<?> ActivityThreadClazz=classloader.loadClass("android.app.ActivityThread");
            Method currentActivityThreadMethod= ActivityThreadClazz.getDeclaredMethod("currentActivityThread");
            currentActivityThreadMethod.setAccessible(true);
            Object activityThreadObj=currentActivityThreadMethod.invoke(null);
            //final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<>();
            Field mPackagesField=ActivityThreadClazz.getDeclaredField("mPackages");
            mPackagesField.setAccessible(true);
            ArrayMap mPackagesObj= (ArrayMap) mPackagesField.get(activityThreadObj);
            WeakReference wr= (WeakReference) mPackagesObj.get(this.getPackageName());
            Object loadedApkObj=wr.get();

            Class LoadedApkClazz=classloader.loadClass("android.app.LoadedApk");
            //private ClassLoader mClassLoader;
            Field mClassLoaderField=LoadedApkClazz.getDeclaredField("mClassLoader");
            mClassLoaderField.setAccessible(true);
            mClassLoaderField.set(loadedApkObj,classloader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2芳来、打破原有的雙親關(guān)系含末,在系統(tǒng)組件類加載器和BootClassLoader的中間插入我們自己的DexClassLoader即可;

public void startTestActivitySecondMethod(Context context,String dexfilepath){

        File optfile=context.getDir("opt_dex",0);
        File libfile=context.getDir("lib_path",0);
        ClassLoader pathClassloader=MainActivity.class.getClassLoader();
        ClassLoader bootClassloader=MainActivity.class.getClassLoader().getParent();
        DexClassLoader dexClassLoader=new DexClassLoader(dexfilepath,optfile.getAbsolutePath(),libfile.getAbsolutePath(),bootClassloader);
        try {
            Field parentField=ClassLoader.class.getDeclaredField("parent");
            parentField.setAccessible(true);
            parentField.set(pathClassloader,dexClassLoader);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

dex整體加密型加固

  • 將Dex整體加密即舌,在需要的時(shí)候解密佣盒,通過(guò)Classloader加入內(nèi)存中。

關(guān)鍵代碼

public class TestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //com.example.myapplication.TestClass.testFunc
        Context appContext=this.getApplicationContext();
        //testDexClassLoader(appContext,"/sdcard/3.dex");
        //startTestActivity(this,"/sdcard/4.dex");
        startTestActivitySecondMethod(this,"/sdcard/6.dex");
    }

    //替換LoadedApk中的mClassLoader 加載自身代碼
    public void replaceClassloader(ClassLoader classloader){
        try {
            Class<?> ActivityThreadClazz=classloader.loadClass("android.app.ActivityThread");
            Method currentActivityThreadMethod= ActivityThreadClazz.getDeclaredMethod("currentActivityThread");
            currentActivityThreadMethod.setAccessible(true);
            Object activityThreadObj=currentActivityThreadMethod.invoke(null);
            //final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<>();
            Field mPackagesField=ActivityThreadClazz.getDeclaredField("mPackages");
            mPackagesField.setAccessible(true);
            ArrayMap mPackagesObj= (ArrayMap) mPackagesField.get(activityThreadObj);
            WeakReference wr= (WeakReference) mPackagesObj.get(this.getPackageName());
            Object loadedApkObj=wr.get();

            Class LoadedApkClazz=classloader.loadClass("android.app.LoadedApk");
            //private ClassLoader mClassLoader;
            Field mClassLoaderField=LoadedApkClazz.getDeclaredField("mClassLoader");
            mClassLoaderField.setAccessible(true);
            mClassLoaderField.set(loadedApkObj,classloader);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }


    }

    public void startTestActivityFirstMethod(Context context,String dexfilepath){

        File optfile=context.getDir("opt_dex",0);
        File libfile=context.getDir("lib_path",0);
        ClassLoader parentClassloader=MainActivity.class.getClassLoader();
        ClassLoader tmpClassLoader=context.getClassLoader();
        DexClassLoader dexClassLoader=new DexClassLoader(dexfilepath,optfile.getAbsolutePath(),libfile.getAbsolutePath(),MainActivity.class.getClassLoader());

        replaceClassloader(dexClassLoader);

        Class<?> clazz=null;
        try {
            clazz = dexClassLoader.loadClass("com.example.myapplication.TestActivity");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        context.startActivity(new Intent(context,clazz));
    }
    public void startTestActivitySecondMethod(Context context,String dexfilepath){

        File optfile=context.getDir("opt_dex",0);
        File libfile=context.getDir("lib_path",0);
        ClassLoader pathClassloader=MainActivity.class.getClassLoader();
        ClassLoader bootClassloader=MainActivity.class.getClassLoader().getParent();
        //加載dex 這里直接加載了未加密的顽聂,可以解密后 再加載肥惭,然后刪除盯仪。也可以替換為memoryclassloader加載 ,實(shí)現(xiàn)不落地加載
        DexClassLoader dexClassLoader=new DexClassLoader(dexfilepath,optfile.getAbsolutePath(),libfile.getAbsolutePath(),bootClassloader);
        try {
            //插入我們自己的dexClassLoader 加入生命周期的處理
            Field parentField=ClassLoader.class.getDeclaredField("parent");
            parentField.setAccessible(true);
            parentField.set(pathClassloader,dexClassLoader);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
/*
* this:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.xyh.loaddex-8_fCxispeBuExjw1ryrRZg==/base.apk"],nativeLibraryDirectories=[/data/app/com.xyh.loaddex-8_fCxispeBuExjw1ryrRZg==/lib/arm64, /system/lib64, /vendor/lib64]]]--parent:dalvik.system.DexClassLoader[DexPathList[[dex file "/sdcard/6.dex"],nativeLibraryDirectories=[/data/user/0/com.xyh.loaddex/app_lib_path, /system/lib64, /vendor/lib64]]]
this:dalvik.system.DexClassLoader[DexPathList[[dex file "/sdcard/6.dex"],nativeLibraryDirectories=[/data/user/0/com.xyh.loaddex/app_lib_path, /system/lib64, /vendor/lib64]]]--parent:java.lang.BootClassLoader@fd4323d
root:java.lang.BootClassLoader@fd4323d*/
        ClassLoader tmpClassloader=pathClassloader;
        ClassLoader parentClassloader=pathClassloader.getParent();
        while(parentClassloader!=null){
            Log.i("xyh","this:"+tmpClassloader+"--parent:"+parentClassloader);
            tmpClassloader=parentClassloader;
            parentClassloader=parentClassloader.getParent();
        }
        Log.i("xyh","root:"+tmpClassloader);
        Class<?> clazz=null;
        try {
            clazz = dexClassLoader.loadClass("com.example.myapplication.TestActivity");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        context.startActivity(new Intent(context,clazz));
    }
}

加固類型-函數(shù)抽取

殼與脫殼之二代殼函數(shù)抽取/#源碼分析

Dalvik指令抽取原理介紹

Android中實(shí)現(xiàn)「類方法指令抽取方式」加固方案原理解析
Android免Root權(quán)限通過(guò)Hook系統(tǒng)函數(shù)修改程序運(yùn)行時(shí)內(nèi)存指令邏輯

  • 在函數(shù)粒度上保護(hù)代碼
  • 將函數(shù)指令全部替換為Nop或無(wú)效指令蜜葱,在執(zhí)行時(shí)還原代碼全景。
  • 主要原理是將原指令置為nop,然后hook,dexFindClass牵囤,找到原始的方法指令指針爸黄,DexCode->insns,替換insns揭鳞。
207665618235835.png

Art 抽取殼介紹

Art下實(shí)現(xiàn)難點(diǎn):dex2oat編譯流程炕贵,dex2oat是可以進(jìn)行脫殼,dex2oat完成了對(duì)抽取的dex進(jìn)行編譯生成了oat文件野崇,后續(xù)的函數(shù)運(yùn)行中称开,從oat中取出函數(shù)編譯生成的二進(jìn)制代碼來(lái)執(zhí)行,因此函數(shù)對(duì)dex填充后舞骆,如果時(shí)機(jī)不對(duì)钥弯,時(shí)機(jī)在dex2oat后记餐,自然從dex2oat后那么我們動(dòng)態(tài)修改的dex中的smali指令流就不會(huì)生效针饥,因?yàn)楹竺鎍pp運(yùn)行調(diào)用的真正的代碼就會(huì)從dex2oat編譯生成的oat文件,和以前的dex無(wú)關(guān)了滞项。因此如果希望填充回去smali指令生效要么禁用dex2oat實(shí)現(xiàn)阻止編譯狈惫,這樣對(duì)加載到內(nèi)存中的dex文件進(jìn)行填充始終會(huì)保持生效睛蛛,要么保持dex2oat編譯,但是還原代碼時(shí)機(jī)要早于dex2oat就ok了胧谈,保證dex2oat再次對(duì)dex編譯的時(shí)候忆肾,dex已經(jīng)是一個(gè)完整dex,不會(huì)影響我們填充的代碼菱肖,但是肯定dex文件存在完整的時(shí)候客冈,可以利用dex2oat編譯的流程進(jìn)行脫殼,一般加殼廠商都是犧牲掉app一部分的運(yùn)行效率稳强,干掉dex2oat的過(guò)程场仲,因?yàn)間oogle本身提倡dex2oat就是為了提升app運(yùn)行效率。
<mark>ART模式下抽取殼 要么阻止dex2oat 要么在dex2oat之前保證加載的dex是一個(gè)完整的dex</mark>
如果選擇第一種方案 , 在 dex2oat 之前進(jìn)行恢復(fù) , 這沒有任何意義 , dex2oat 編譯后 , 生成的 oat 文件是完整的 , 此時(shí) 可以 完整的將 oat 文件 dump 到 SD 卡中 , 基本等于沒有加固 , 還是一個(gè)一代殼 ;
因此 , 大部分加固廠商 , 選擇 禁用 dex2oat 機(jī)制 ; 這樣處于安全考慮 , 犧牲了應(yīng)用的運(yùn)行效率 ;

145113619231589.png
  • classloader加載dex的時(shí)候 會(huì)進(jìn)行dex2oat的優(yōu)化退疫,將dex的解釋執(zhí)行渠缕,變成直接執(zhí)行,提升運(yùn)行效率褒繁。
  • 7.0之后會(huì)根據(jù)函數(shù)使用頻率進(jìn)行dex2oat的優(yōu)化亦鳞,并不會(huì)直接全部dex2oat

https://source.android.google.cn/devices/tech/dalvik/configure
ART 使用預(yù)先 (AOT) 編譯,并且從 Android 7.0(代號(hào) Nougat,簡(jiǎn)稱 N)開始結(jié)合使用 AOT燕差、即時(shí) (JIT) 編譯和配置文件引導(dǎo)型編譯遭笋。所有這些編譯模式的組合均可配置,我們將在本部分中對(duì)此進(jìn)行介紹谁不。例如坐梯,Pixel 設(shè)備配置了以下編譯流程:
7.0之后最初安裝應(yīng)用時(shí)不進(jìn)行任何 AOT 編譯徽诲。應(yīng)用前幾次運(yùn)行時(shí)刹帕,系統(tǒng)會(huì)對(duì)其進(jìn)行解譯,并對(duì)經(jīng)常執(zhí)行的方法進(jìn)行 JIT 編譯谎替。
當(dāng)設(shè)備閑置和充電時(shí)偷溺,編譯守護(hù)程序會(huì)運(yùn)行,以便根據(jù)在應(yīng)用前幾次運(yùn)行期間生成的配置文件對(duì)常用代碼進(jìn)行 AOT 編譯钱贯。
下一次重新啟動(dòng)應(yīng)用時(shí)將會(huì)使用配置文件引導(dǎo)型代碼挫掏,并避免在運(yùn)行時(shí)對(duì)已經(jīng)過(guò)編譯的方法進(jìn)行 JIT 編譯。在應(yīng)用后續(xù)運(yùn)行期間經(jīng)過(guò) JIT 編譯的方法將會(huì)添加到配置文件中秩命,然后編譯守護(hù)程序?qū)?huì)對(duì)這些方法進(jìn)行 AOT 編譯尉共。
ART 的運(yùn)作方式 在 Android O 版本中,將會(huì)生成以下文件:
.vdex:其中包含 APK 的未壓縮 DEX 代碼弃锐,以及一些旨在加快驗(yàn)證速度的元數(shù)據(jù)袄友。
使用010editer就可以找到dex
.odex:其中包含 APK 中已經(jīng)過(guò) AOT 編譯的方法代碼。
oatdump 可以反編譯odex文件霹菊,可以dump出函數(shù)的smali指令
.art (optional):其中包含 APK 中列出的某些字符串和類的 ART 內(nèi)部表示剧蚣,用于加快應(yīng)用啟動(dòng)速度。
全部進(jìn)行oat優(yōu)化的話旋廷,非常耗時(shí)鸠按,所以7.0之后選取了保守的優(yōu)化策略
odex 優(yōu)化后,oatdump還是可以dump出原始的smali指令饶碘,只是優(yōu)化后的函數(shù) 在CODE段目尖,會(huì)有優(yōu)化后的二進(jìn)制匯編指令,在執(zhí)行的時(shí)候會(huì)直接進(jìn)入quick模式扎运,執(zhí)行匯編指令瑟曲,加快運(yùn)行速度。具有CODE段后绪囱,將不再進(jìn)入解釋執(zhí)行模式测蹲。

  • art抽取殼必須在dex2oat之前還原,否則dex2oat之后鬼吵,就無(wú)法還原扣甲。要么阻止dex2oat 要么提前還原
  • 首先要干掉Dex2oat的過(guò)程。可以參考github TurboDex(快速加載dex 阻止dex2oat) dex2oat 非常耗時(shí)琉挖;不進(jìn)行oat的話 會(huì)影響dex的運(yùn)行效率启泣。
  • 阻止了dex2oat后 所有代碼都是解釋執(zhí)行了。那么必然會(huì)去內(nèi)存中尋找ArtMethod的code_item去執(zhí)行
  • 那么在art類加載的時(shí)候還原code_item就可以正常去執(zhí)行了
  • 剩下的和dalvik基本一致
    • 1示辈、先通過(guò)010edite將一個(gè)函數(shù)全部抽取為nop
    • 2寥茫、hook art loadmethod的過(guò)程
    • 3、將原始的指令還原到artmethod中

ART的類加載執(zhí)行流程

強(qiáng)烈建議閱讀此文章
ART 在 Android 安全攻防中的應(yīng)用

關(guān)鍵代碼

#include <jni.h>
#include <string>
#include <unistd.h>
#include <android/log.h>
#include <fcntl.h>
#include <asm/fcntl.h>
#include <sys/mman.h>
#include <dlfcn.h>
//import c header
extern "C" {
#include "hook/dlfcn/dlfcn_compat.h"
#include "hook/include/inlineHook.h"
}
typedef unsigned char byte;
#define TAG "SecondShell"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
struct DexFile {
    // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
    // The class we are a part of.
    uint32_t declaring_class_;
    // Access flags; low 16 bits are defined by spec.
    void *begin;
    /* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
    // Offset to the CodeItem.
    uint32_t size;
};
struct ArtMethod {
    // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
    // The class we are a part of.
    uint32_t declaring_class_;
    // Access flags; low 16 bits are defined by spec.
    uint32_t access_flags_;
    /* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
    // Offset to the CodeItem.
    uint32_t dex_code_item_offset_;
    // Index into method_ids of the dex file associated with this method.
    uint32_t dex_method_index_;
};

void* *(*oriexecve)(const char *__file, char *const *__argv, char *const *__envp);

void* *myexecve(const char *__file, char *const *__argv, char *const *__envp) {
    LOGD("process:%d,enter execve:%s", getpid(), __file);
    if (strstr(__file, "dex2oat")) {
        return NULL;
    } else {
        return oriexecve(__file, __argv, __envp);
    }


}

//void ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it,Handle<mirror::Class> klass, ArtMethod* dst)
void *(*oriloadmethod)(void *, void *, void *, void *, void *);

void *myloadmethod(void *a, void *b, void *c, void *d, void *e) {
    LOGD("process:%d,before run loadmethod:", getpid());
    struct ArtMethod *artmethod = (struct ArtMethod *) e;
    struct DexFile *dexfile = (struct DexFile *) b;
    LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d", getpid(), dexfile->begin,
         dexfile->size);//0,57344
    char dexfilepath[100] = {0};
    sprintf(dexfilepath, "/sdcard/%d_%d.dex", dexfile->size, getpid());
    int fd = open(dexfilepath, O_CREAT | O_RDWR, 0666);
    if (fd > 0) {
        write(fd, dexfile->begin, dexfile->size);
        close(fd);
    }

    void *result = oriloadmethod(a, b, c, d, e);
    LOGD("process:%d,enter loadmethod:code_offset:%d,idx:%d", getpid(),
         artmethod->dex_code_item_offset_, artmethod->dex_method_index_);

    byte *code_item_addr = static_cast<byte *>(dexfile->begin) + artmethod->dex_code_item_offset_;
    LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d,beforedumpcodeitem:%p", getpid(),
         dexfile->begin, dexfile->size, code_item_addr);


    if (artmethod->dex_method_index_ == 15203) {//TestClass.testFunc->methodidx
        LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d,start repire method", getpid(),
             dexfile->begin, dexfile->size);
        byte *code_item_addr = (byte *) dexfile->begin + artmethod->dex_code_item_offset_;
        LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d,beforedumpcodeitem:%p", getpid(),
             dexfile->begin, dexfile->size, code_item_addr);

        int result = mprotect(dexfile->begin, dexfile->size, PROT_WRITE);
        byte *code_item_start = static_cast<byte *>(code_item_addr) + 16;
        LOGD("process:%d,enter loadmethod:dexfilebegin:%p,size:%d,code_item_start:%p", getpid(),
             dexfile->begin, dexfile->size, code_item_start);
        byte inst[16] = {0x1a, 0x00, 0xed, 0x34, 0x1a, 0x01, 0x43, 0x32, 0x71, 0x20, 0x91, 0x05,
                         0x10, 0x00, 0x0e, 0x00};
        for (int i = 0; i < sizeof(inst); i++) {
            code_item_start[i] = inst[i];
        }
        //2343->i am from com.kanxue.test02.TestClass.testFunc
        code_item_start[2] = 0x43;//34ed->kanxue
        code_item_start[3] = 0x23;
        memset(dexfilepath, 0, 100);
        sprintf(dexfilepath, "/sdcard/%d_%d.dex_15203_2", dexfile->size, getpid());
        fd = open(dexfilepath, O_CREAT | O_RDWR, 0666);
        if (fd > 0) {
            write(fd, dexfile->begin, dexfile->size);
            close(fd);
        }
    }
    LOGD("process:%d,after loadmethod:code_offset:%d,idx:%d", getpid(),
         artmethod->dex_code_item_offset_, artmethod->dex_method_index_);//0,57344
    return result;

}

void hooklibc() {
    LOGD("go into hooklibc");
    //7.0 命名空間限制
    void *libc_addr = dlopen_compat("libc.so", RTLD_NOW);
    void *execve_addr = dlsym_compat(libc_addr, "execve");
    if (execve_addr != NULL) {
        if (ELE7EN_OK == registerInlineHook((uint32_t) execve_addr, (uint32_t) myexecve,
                                            (uint32_t **) &oriexecve)) {
            if (ELE7EN_OK == inlineHook((uint32_t) execve_addr)) {
                LOGD("inlineHook execve success");
            } else {
                LOGD("inlineHook execve failure");
            }
        }
    }
}

void hookART() {
    LOGD("go into hookART");
    void *libart_addr = dlopen_compat("/system/lib/libart.so", RTLD_NOW);
    if (libart_addr != NULL) {
        void *loadmethod_addr = dlsym_compat(libart_addr,
                                             "_ZN3art11ClassLinker10LoadMethodERKNS_7DexFileERKNS_21ClassDataItemIteratorENS_6HandleINS_6mirror5ClassEEEPNS_9ArtMethodE");
        if (loadmethod_addr != NULL) {
            if (ELE7EN_OK == registerInlineHook((uint32_t) loadmethod_addr, (uint32_t) myloadmethod,
                                                (uint32_t **) &oriloadmethod)) {
                if (ELE7EN_OK == inlineHook((uint32_t) loadmethod_addr)) {
                    LOGD("inlineHook loadmethod success");
                } else {
                    LOGD("inlineHook loadmethod failure");
                }
            }
        }
    }


}

extern "C" JNIEXPORT jstring JNICALL
Java_com_kanxue_secondshell_180_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "ART SecondShell";
    return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT void JNICALL
Java_com_kanxue_secondshell_180_MainActivity_SecondShell(
        JNIEnv *env,
        jobject /* this */) {
    hooklibc();//hook execve 禁止執(zhí)行dex2oat
    hookART();//hook LoadMethod 修復(fù)被抽取的artmethod,并在修復(fù)前修復(fù)后dumpdex
    return;
}

加固類型-VMP矾麻,Dex2C

  • VMP 自定義解釋器纱耻,解釋執(zhí)行自定義的指令。
  • Dex2c 在編譯時(shí)险耀,將java代碼編譯成c代碼 增加破解難度
  • 未來(lái)加固的主要方向->VMP弄喘,Dex2C
    • VMP 會(huì)把java函數(shù)native化,原理:VMP是做虛擬機(jī)解釋器
      • VMP的多個(gè)native函數(shù) 很可能是一個(gè)地址甩牺。多個(gè)native函數(shù) 都是調(diào)用的一個(gè)地方
      • 破解需要找到解釋器蘑志,找到smaili的映射關(guān)系即可恢復(fù)
      • github 搜索 ADVMP 可以參考 沒具體研究
    • Dex2c 開源項(xiàng)目 dcc,原理:對(duì)java語(yǔ)義分析贬派,重新生成native函數(shù)急但。
      • python dcc.py dcc.apk -o dcc_out.apk 使用DCC增加保護(hù),java函數(shù)會(huì)變成native函數(shù)搞乏。 只建議部分函數(shù)增加保護(hù)波桩,否則會(huì)嚴(yán)重影響性能
      • dcc可以將APK的java代碼 轉(zhuǎn)化為native代碼,并且可以增加ollvm的混淆
      • dcc的native注冊(cè)函數(shù) 基本是一一對(duì)應(yīng)
      • 基本不太好破解查描。突委。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冬三,隨后出現(xiàn)的幾起案子匀油,更是在濱河造成了極大的恐慌,老刑警劉巖勾笆,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敌蚜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡窝爪,警方通過(guò)查閱死者的電腦和手機(jī)弛车,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蒲每,“玉大人纷跛,你說(shuō)我怎么就攤上這事⊙樱” “怎么了贫奠?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵唬血,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我唤崭,道長(zhǎng)拷恨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任谢肾,我火速辦了婚禮腕侄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芦疏。我一直安慰自己冕杠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布眯分。 她就那樣靜靜地躺著拌汇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弊决。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天魁淳,我揣著相機(jī)與錄音飘诗,去河邊找鬼。 笑死界逛,一個(gè)胖子當(dāng)著我的面吹牛昆稿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播息拜,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼溉潭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了少欺?” 一聲冷哼從身側(cè)響起喳瓣,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赞别,沒想到半個(gè)月后畏陕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仿滔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年惠毁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崎页。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鞠绰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出飒焦,到底是詐尸還是另有隱情蜈膨,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站丈挟,受9級(jí)特大地震影響刁卜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜曙咽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一蛔趴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧例朱,春花似錦孝情、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至渔隶,卻和暖如春羔挡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背间唉。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工绞灼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呈野。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓低矮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親被冒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子军掂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容