0x03 DexHunter代碼分析
DexHunter 實現中,只需要修改一處文件:dalvik\vm\native\dalvik_system_DexFile.cpp
下面是BeyondCompare比對:

首先看一下DexHunter的設計原理:


APP 啟動時,通過freature string定位dex在內存中位置,並讀取classdef塊之前的內存為part1,讀取classdef之后的內存為data。遍歷class_def_item結構,生成文件classdef,並通過code_item_off判斷具體的類方法是否在dex范圍內,若不在,則寫extra文件。


描述幾個問題:
-
從哪里dump出dex文件
dex文件打開時
類加載時
類初始化時
類方法調用時
DexHunter中,我們關注,ClassLoader.loadClass->Dalvik_dalvik_system_DexFile_defineClassNative這個函數,它實現了類的加載,實現過程如下:


選擇脫殼的時機應是在APP的第一個類加載的時候,為什么呢?
-
類加載之前,類的內容是在內存當中的
-
當類初始化時,該內存的內容可能會被動態修改
-
在一個類方法被調用前,code_item或指令肯定是可用的
那如何做呢?
我們要主動加載並初始化所有的類;
因此,我們代碼的注入點,應該是Dalvik_dalvik_system_DexFile_defineClassNative()函數的clazz = dvmDefineClass(pDvmDex, descriptor, loader);語句之前;即在APP加載第一個類之前完成;通過dvmDefineClass主動遍歷class_def_item加載每個類,並調用dvmIsClassInitialized和dvmInitClass函數初始化之。
初始化完成之后,內存中的就是將執行的代碼,像梆梆加固針對每個方法進行的加密,會在運行時解密、運行完成后清理內存並再次加密,通過這種方法就可以過掉;因為我們模擬了這樣一次調用過程;
下面是我加入注釋的代碼:
//------------------------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}; //feature string
static char dumppath[100]={0}; //dump的文件路徑
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); //讀feature string
dexname[strlen(dexname)-1]=0;
fgets(dumppath,99,fp);
dumppath[strlen(dumppath)-1]=0; //取dump路徑
fclose(fp);
fp=NULL;
}
struct sigevent sev;
sev.sigev_notify=SIGEV_THREAD;
sev.sigev_value.sival_ptr=&timerId;
sev.sigev_notify_function=timer_thread;
sev.sigev_notify_attributes = NULL;
timer_create(CLOCK_REALTIME,&sev,&timerId);
struct itimerspec ts;
ts.it_value.tv_sec=5;
ts.it_value.tv_nsec=0;
ts.it_interval.tv_sec=0;
ts.it_interval.tv_nsec=0;
timer_settime(timerId,0,&ts,NULL);
return NULL;
}
/*
這里是class_data_item的前4項,稱為ClassDataHeader
Dex File->class_defs->class_def_item(class_data_offset)->class_data_item->ClassDataHeader
*/
void ReadClassDataHeader(const uint8_t** pData, DexClassDataHeader *pHeader)
{
pHeader->staticFieldsSize = readUnsignedLeb128(pData);
pHeader->instanceFieldsSize = readUnsignedLeb128(pData);
pHeader->directMethodsSize = readUnsignedLeb128(pData);
pHeader->virtualMethodsSize = readUnsignedLeb128(pData);
}
/*
下面兩個函數,分別讀class_data_item Header下的內容,分Field和Method
*/
void ReadClassDataField(const uint8_t** pData, DexField* pField)
{
pField->fieldIdx = readUnsignedLeb128(pData);
pField->accessFlags = readUnsignedLeb128(pData);
}
void ReadClassDataMethod(const uint8_t** pData, DexMethod* pMethod)
{
pMethod->methodIdx = readUnsignedLeb128(pData);
pMethod->accessFlags = readUnsignedLeb128(pData);
pMethod->codeOff = readUnsignedLeb128(pData);
}
/*
解析class_data_item結構,使用到上面3個函數,分別解析,Header、Field和Method部分
*/
DexClassData* ReadClassData(const uint8_t** pData)
{
DexClassDataHeader header;
if (*pData == NULL) {
return NULL;
}
//讀取 class_data_item的Header
ReadClassDataHeader(pData, &header);
size_t resultSize = sizeof(DexClassData) + (header.staticFieldsSize * sizeof(DexField)) + (header.instanceFieldsSize * sizeof(DexField)) + (header.directMethodsSize * sizeof(DexMethod)) + (header.virtualMethodsSize * sizeof(DexMethod));
DexClassData* result = (DexClassData*) malloc(resultSize); //result指向class_data_item並返回
if (result == NULL) {
return NULL;
}
uint8_t* ptr = ((uint8_t*) result) + sizeof(DexClassData); //指向class_data_item的staic_fields偏移
result->header = header;
//以下依次讀class_data_item的staticFields,instanceFields,directMethods和virtualMethods域大小————————begain
if (header.staticFieldsSize != 0) {
result->staticFields = (DexField*) ptr;
ptr += header.staticFieldsSize * sizeof(DexField);
} else {
result->staticFields = NULL;
}
if (header.instanceFieldsSize != 0) {
result->instanceFields = (DexField*) ptr;
ptr += header.instanceFieldsSize * sizeof(DexField);
} else {
result->instanceFields = NULL;
}
if (header.directMethodsSize != 0) {
result->directMethods = (DexMethod*) ptr;
ptr += header.directMethodsSize * sizeof(DexMethod);
} else {
result->directMethods = NULL;
}
if (header.virtualMethodsSize != 0) {
result->virtualMethods = (DexMethod*) ptr;
} else {
result->virtualMethods = NULL;
}
//以下依次讀class_data_item的staticFields,instanceFields,directMethods和virtualMethods域大小————————end
//以下依次讀staticFields,instanceFields,directMethods,virtualMethods域內容————————begain
for (uint32_t i = 0; i < header.staticFieldsSize; i++) {
ReadClassDataField(pData, &result->staticFields[i]);
}
for (uint32_t i = 0; i < header.instanceFieldsSize; i++) {
ReadClassDataField(pData, &result->instanceFields[i]);
}
for (uint32_t i = 0; i < header.directMethodsSize; i++) {
ReadClassDataMethod(pData, &result->directMethods[i]);
}
for (uint32_t i = 0; i < header.virtualMethodsSize; i++) {
ReadClassDataMethod(pData, &result->virtualMethods[i]);
}
//以下依次讀staticFields,instanceFields,directMethods,virtualMethods域內容————————end
return result;
}
/*
class_data_item中的一些域是用LEB128算法編碼的
*/
void writeLeb128(uint8_t ** ptr, uint32_t data)
{
while (true) {
uint8_t out = data & 0x7f;
if (out != data) {
*(*ptr)++ = out | 0x80;
data >>= 7;
} else {
*(*ptr)++ = out;
break;
}
}
}
/*
此函數讀取class_data_item,並將內容用writeLeb128轉碼后返回
*/
uint8_t* EncodeClassData(DexClassData *pData, int& len)
{
len=0;
len+=unsignedLeb128Size(pData->header.staticFieldsSize);
len+=unsignedLeb128Size(pData->header.instanceFieldsSize);
len+=unsignedLeb128Size(pData->header.directMethodsSize);
len+=unsignedLeb128Size(pData->header.virtualMethodsSize);
if (pData->staticFields) {
for (uint32_t i = 0; i < pData->header.staticFieldsSize; i++) {
len+=unsignedLeb128Size(pData->staticFields[i].fieldIdx);
len+=unsignedLeb128Size(pData->staticFields[i].accessFlags);
}
}
if (pData->instanceFields) {
for (uint32_t i = 0; i < pData->header.instanceFieldsSize; i++) {
len+=unsignedLeb128Size(pData->instanceFields[i].fieldIdx);
len+=unsignedLeb128Size(pData->instanceFields[i].accessFlags);
}
}
if (pData->directMethods) {
for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
len+=unsignedLeb128Size(pData->directMethods[i].methodIdx);
len+=unsignedLeb128Size(pData->directMethods[i].accessFlags);
len+=unsignedLeb128Size(pData->directMethods[i].codeOff);
}
}
if (pData->virtualMethods) {
for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
len+=unsignedLeb128Size(pData->virtualMethods[i].methodIdx);
len+=unsignedLeb128Size(pData->virtualMethods[i].accessFlags);
len+=unsignedLeb128Size(pData->virtualMethods[i].codeOff);
}
}
uint8_t * store = (uint8_t *) malloc(len);
if (!store) {
return NULL;
}
uint8_t * result=store;
writeLeb128(&store,pData->header.staticFieldsSize);
writeLeb128(&store,pData->header.instanceFieldsSize);
writeLeb128(&store,pData->header.directMethodsSize);
writeLeb128(&store,pData->header.virtualMethodsSize);
if (pData->staticFields) {
for (uint32_t i = 0; i < pData->header.staticFieldsSize; i++) {
writeLeb128(&store,pData->staticFields[i].fieldIdx);
writeLeb128(&store,pData->staticFields[i].accessFlags);
}
}
if (pData->instanceFields) {
for (uint32_t i = 0; i < pData->header.instanceFieldsSize; i++) {
writeLeb128(&store,pData->instanceFields[i].fieldIdx);
writeLeb128(&store,pData->instanceFields[i].accessFlags);
}
}
if (pData->directMethods) {
for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
writeLeb128(&store,pData->directMethods[i].methodIdx);
writeLeb128(&store,pData->directMethods[i].accessFlags);
writeLeb128(&store,pData->directMethods[i].codeOff);
}
}
if (pData->virtualMethods) {
for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
writeLeb128(&store,pData->virtualMethods[i].methodIdx);
writeLeb128(&store,pData->virtualMethods[i].accessFlags);
writeLeb128(&store,pData->virtualMethods[i].codeOff);
}
}
free(pData);
return result;
}
uint8_t* codeitem_end(const u1** pData)
{
uint32_t num_of_list = readUnsignedLeb128(pData);
for (;num_of_list>0;num_of_list--) {
int32_t num_of_handlers=readSignedLeb128(pData);
int num=num_of_handlers;
if (num_of_handlers<=0) {
num=-num_of_handlers;
}
for (; num > 0; num--) {
readUnsignedLeb128(pData);
readUnsignedLeb128(pData);
}
if (num_of_handlers<=0) {
readUnsignedLeb128(pData);
}
}
return (uint8_t*)(*pData);
}
代碼未完,下一篇繼續;
