【Android 逆向】Dalvik 函数抽取加壳 ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数分析 )
文章目錄
- 前言
- 一、Class.cpp#dvmDefineClass 函數分析
- 二、Class.cpp#findClassNoInit 函數分析
- 三、DexFile.cpp#dexFindClass 函數分析
前言
上一篇博客 【Android 逆向】Dalvik 函數抽取加殼 ( 類加載流程分析 | native 函數查詢 | dalvik_system_DexFile.cpp#defineClassNative 函數 ) 中 , dalvik_system_DexFile.cpp#Dalvik_dalvik_system_DexFile_defineClassNative 函數中 , 調用了 Class.cpp#dvmDefineClass 函數 ;
一、Class.cpp#dvmDefineClass 函數分析
在 Class.cpp#dvmDefineClass 函數中 , 主要調用了 Class.cpp#findClassNoInit 函數 ;
Class.cpp#dvmDefineClass 函數源碼 :
/** 從指定的DEX文件加載命名類(按描述符)。* 由類裝入器用于從* 虛擬機管理的DEX。*/ ClassObject* dvmDefineClass(DvmDex* pDvmDex, const char* descriptor,Object* classLoader) {assert(pDvmDex != NULL);return findClassNoInit(descriptor, classLoader, pDvmDex); }源碼路徑 : /dalvik/vm/oo/Class.cpp#dvmDefineClass
二、Class.cpp#findClassNoInit 函數分析
在 Class.cpp#findClassNoInit 函數中 ,
先調用 dvmLookupClass 函數 , 查詢當前已經加載的類 , 一般情況下 , 第一次加載 , 查詢到的結果是空的 ;
// 查詢當前已經加載的類 , 第一次加載 , 一般查詢不到 clazz = dvmLookupClass(descriptor, loader, true);然后進入到 clazz == NULL 分支 , 執行 dexFindClass 函數 , 此處調用了 dexFindClass , 就是在該函數中 , 恢復被抽取的函數 , 《Android中實現「類方法指令抽取方式」加固方案原理解析 | 作者 : 姜維》 博客 中恢復抽取函數的 hook 點 , 就是 dexFindClass 中 ;
pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);參考 【Android 逆向】Dalvik 函數抽取加殼 ( Dalvik 下的函數指令抽取與恢復 | dex 函數指令恢復時機點 | 類加載流程 : 加載、鏈接、初始化 ) 博客 ;
Class.cpp#findClassNoInit 函數源碼 :
/** 查找命名類(按描述符)。如果還沒有加載,* 我們加載并鏈接它,但不執行<clinit>。(越南船民* 事件可能導致初始化的特定限制。)* * 如果“pDexFile”為空,我們將在bootclasspath中搜索條目。* * 失敗時,返回NULL并引發異常。* * TODO:我們需要返回一個是否加載了類的指示* 使用現有的定義。如果有人故意加載* 在同一個類加載器中初始化兩次,它們將得到LinkageError,* 但無意中同時引用類應該“正常工作”。*/ static ClassObject* findClassNoInit(const char* descriptor, Object* loader,DvmDex* pDvmDex) {// 查詢當前已經加載的類 , 第一次加載 , 一般查詢不到 clazz = dvmLookupClass(descriptor, loader, true);if (clazz == NULL) {// 第一次查詢 , 肯定會進入該分支const DexClassDef* pClassDef;dvmMethodTraceClassPrepBegin();profilerNotified = true;#if LOG_CLASS_LOADINGu8 startTime = dvmGetThreadCpuTimeNsec(); #endifif (pDvmDex == NULL) {assert(loader == NULL); /* shouldn't be here otherwise */pDvmDex = searchBootPathForClass(descriptor, &pClassDef);} else {// 此處調用了 dexFindClass , 就是在該函數中 , 恢復被抽取的函數 //《Android中實現「類方法指令抽取方式」加固方案原理解析 | 作者 : 姜維》 博客// 中恢復抽取函數的 hook 點 , 就是 dexFindClass 中pClassDef = dexFindClass(pDvmDex->pDexFile, descriptor);}return clazz; }源碼路徑 : /dalvik/vm/oo/Class.cpp#findClassNoInit
三、DexFile.cpp#dexFindClass 函數分析
在該 DexFile.cpp#dexFindClass 函數 中 , 恢復被抽取的函數 , 《Android中實現「類方法指令抽取方式」加固方案原理解析 | 作者 : 姜維》 博客 中恢復抽取函數的 hook 點 , 就是 dexFindClass 中 ;
DexFile.cpp#dexFindClass 函數源碼 :
/** 按描述符查找類定義條目。* * “描述符”應該像“Landroid/debug/Stuff;”。*/ const DexClassDef* dexFindClass(const DexFile* pDexFile,const char* descriptor) {const DexClassLookup* pLookup = pDexFile->pClassLookup;u4 hash;int idx, mask;hash = classDescriptorHash(descriptor);mask = pLookup->numEntries - 1;idx = hash & mask;/** 搜索,直到找到匹配的條目或空插槽。*/while (true) {int offset;offset = pLookup->table[idx].classDescriptorOffset;if (offset == 0)return NULL;if (pLookup->table[idx].classDescriptorHash == hash) {const char* str;str = (const char*) (pDexFile->baseAddr + offset);if (strcmp(str, descriptor) == 0) {return (const DexClassDef*)(pDexFile->baseAddr + pLookup->table[idx].classDefOffset);}}idx = (idx + 1) & mask;} }源碼路徑 : /dalvik/libdex/DexFile.cpp#dexFindClass
總結
以上是生活随笔為你收集整理的【Android 逆向】Dalvik 函数抽取加壳 ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数分析 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 逆向】Dalvik 函
- 下一篇: 【Groovy】字符串 ( 字符串类型变