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); }
代碼未完,下一篇繼續;