Android 逆向Dalvik 函数抽取加壳 ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数分析 )(代
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 逆向Dalvik 函数抽取加壳 ( 类加载流程分析 | 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_LOADING
u8 startTime = dvmGetThreadCpuTimeNsec();
#endif
if (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;
以上是关于Android 逆向Dalvik 函数抽取加壳 ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数分析 )(代的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向Dalvik 函数抽取加壳 ( 类加载流程分析 | native 函数查询 | dalvik_system_DexFile.cpp#defineClassNative 函数 )(代
Android 逆向Dalvik 函数抽取加壳 ( 类加载流程分析 | DexPathList#findClass 函数分析 | DexFile#loadClassBinaryName 函数 )(代码
Android 逆向Dalvik 函数抽取加壳 ( 类加载流程分析 | Class.cpp#findClassNoInit 函数 | DexFile.cpp#dexFindClass 函数分析 )(代
Android 逆向Dalvik 函数抽取加壳 ( 类加载流程分析 | ClassLoader#loadClass 函数分析 | BaseDexClassLoader#findClass 分析 )(代
Android 逆向ART 函数抽取加壳 ⑥ ( 函数抽取后续操作 “ 还原被抽取的函数 “ | LoadClass 类加载 | LoadClassMembers 类成员加载 )
Android 逆向加壳技术识别 ( 函数抽取 与 Native 化加壳的区分 | VMP 加壳与 Dex2C 加壳的区分 )