0x00
这篇文章我们分析Android脱壳神器DexHunter的源代码。DexHunter作者也写了一篇介绍它的文章从Android运行时出发,打造我们的脱壳神器。DexHunter源代码位于https://github.com/zyq8709/DexHunter。
0x01
DexHunter 实现中,只需要修改一处文件:dalvik\vm\native\dalvik_system_DexFile.cpp
下面是BeyondCompare比对:
我们看到DexHunter的代码都位于系统源代码vm目录下,所以要运行DexHunter需要dalvik\vm\native\dalvik_system_DexFile.cpp代码,然后在源码环境下编译,最后刷机运行。
0x02
核心原理请参考从Android运行时出发,打造我们的脱壳神器,简单的从代码角度说,在Dalvik_dalvik_system_DexFile_defineClassNative中插入代码来修复被破坏的dex,原理有两个:
1、在DVM中:
显式加载:
ClassLoader.loadClass对应Dalvik_dalvik_system_DexFile_defineClassNative
Class.forName对应Dalvik_java_lang_Class_classForName
隐式加载:
对应dvmResolveClass
如下图:
第一点说明了时机,也就是为什么在Dalvik_dalvik_system_DexFile_defineClassNative插入代码。
2、执行dvmDefineClass,形成的ClassObject结构体的变量都是有效的。dvmDefineClass会在我们插入的代码中调用,详见后面的分析。
0x03
下面用注释的方式来分析源代码。
分析之前先附上两张图,有助于分析。
图 1
其中baseAddr指向DexHeader的首地址,图中有错误。下文中经常看到mem->addr指向DexOptHeader的首地址。
再附上一张图,分析时会用到:
图 2
//------------------------added begin----------------------//
#include <asm/siginfo.h>
#include "libdex/DexClass.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
static char dexname[100]={0};
static char dumppath[100]={0};
static bool readable=true;
static pthread_mutex_t read_mutex;
static bool flag=true;
static pthread_mutex_t mutex;
static bool timer_flag=true;
static timer_t timerId;
struct arg{
DvmDex* pDvmDex;
Object * loader;
}param;
void timer_thread(sigval_t)
{
timer_flag=false;
timer_delete(timerId);
ALOGI("GOT IT time up");
}
void* ReadThread(void *arg){
FILE *fp = NULL;
while (dexname[0]==0||dumppath[0]==0) {
fp=fopen("/data/dexname", "r");
if (fp==NULL) {
sleep(1);
continue;
}
fgets(dexname,99,fp);//从/data/dexname获取字符串赋值给dexname,github中已经给出了,是/data/data/com.example.seventyfour.tencenttest/files/libmobisecy1.zip,这是用来脱阿里壳子时使用的
dexname[strlen(dexname)-1]=0;
fgets(dumppath,99,fp);//这是生成4个文件的总目录/data/data/com.example.seventyfour.tencenttest/,后面我们会看到4个文件分别是part1,data,classdef,ext