本文博客地址: http://blog.csdn.net/qq1084283172/article/details/78494620java
DexHunter脫殼工具在Dalvik虛擬機模式下的脫殼原理分析,在前面的博客中已經提到了,可是自我感受分析和理解的還不夠透徹,後面又對DexHunter脫殼工具的源碼再閱讀了幾遍,總算是把DexHunter脫殼工具在Dalvik虛擬機模式下和ART虛擬機模式下的脫殼原理理解清楚了。關於DexHunter脫殼工具在Dalvik虛擬機模式下的脫殼原理分析,已經準備了一篇博客想詳細和深刻的講一講,一直擱置了沒有完成;原本還計劃把DexHunter脫殼工具在ART虛擬機模式下的脫殼原理也詳細說一說,看來是不可能了。有關Android加固脫殼和Hook的好幾個源碼工程都看的差很少了,由於各類事情和狀態很差,懶得動筆了。android
在理解DexHunter脫殼工具在ART虛擬機模式下的脫殼原理以前,建議先閱讀一下老羅的博客瞭解一下Android的ART虛擬機模式下的類加載和dex文件的優化過程,《Android運行時ART加載OAT文件的過程分析》這篇博客須要好好讀一讀。DexHunter在ART虛擬機模式下的脫殼編譯配置主要是針對源碼文件 /art/runtime/class_linker.cc 進行修改,以Android 4.4.4 r1的源碼文件爲示例 http://androidxref.com/4.4.4_r1/xref/art/runtime/class_linker.cc,而後對Android系統源碼進行從新編譯生成Android系統的鏡像文件,刷到手機設備或者Android模擬器上使用,用來進行DexHunter在ART虛擬機模式下的脫殼操做。函數
//-----------------------added begin-----------------------// /** * // OAT文件裏面的oatdata段的開始儲存着一個OAT頭OatHeader const OatHeader& OatFile::GetOatHeader() const { return *reinterpret_cast<const OatHeader*>(Begin()); } // OAT文件裏面的oatdata段開始地址 const byte* OatFile::Begin() const { CHECK(begin_ != NULL); return begin_; } // OAT文件裏面的oatexec段的結束地址 const byte* OatFile::End() const { CHECK(end_ != NULL); return end_; } // OAT文件裏面的oatdata段的開始儲存着一個OAT頭,這個OAT頭經過類OatHeader描述 class PACKED(4) OatHeader { public: ...... private: uint8_t magic_[4]; // 標識OAT文件的魔法數,等於‘oat\n’ uint8_t version_[4]; // OAT文件版本號,目前的值等於‘00七、0’。 uint32_t adler32_checksum_; // OAT頭部檢驗和 // 本地機指令集,有四種取值,分別爲 kArm(1)、kThumb2(2)、kX86(3)和kMips(4)。 InstructionSet instruction_set_; // OAT文件包含的DEX文件個數。 uint32_t dex_file_count_; // oatexec段開始位置與oatdata段開始位置的相對偏移值。 uint32_t executable_offset_; // 在由打包在應用程序裏面的classes.dex生成的OAT文件的oatdata段頭部中,下述七個成員變量的值均等於0。 uint32_t interpreter_to_interpreter_bridge_offset_; uint32_t interpreter_to_compiled_code_bridge_offset_; uint32_t jni_dlsym_lookup_offset_; uint32_t portable_resolution_trampoline_offset_; uint32_t portable_to_interpreter_bridge_offset_; uint32_t quick_resolution_trampoline_offset_; uint32_t quick_to_interpreter_bridge_offset_; // 用來建立Image空間的OAT文件的檢驗和。 uint32_t image_file_location_oat_checksum_; // 用來建立Image空間的OAT文件的oatdata段在內存的位置。 uint32_t image_file_location_oat_data_begin_; // 用來建立Image空間的文件的路徑的大小。 uint32_t image_file_location_size_; // 用來建立Image空間的文件的路徑的在內存中的地址。 uint8_t image_file_location_data_[0]; // note variable width data at end ...... }; // 參考:http://blog.csdn.net/Luoshengyang/article/details/39307813 **/ #include <asm/siginfo.h> #define LOGI 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{ const DexFile* dex_file; mirror::ClassLoader* class_loader; ClassLinker* cl; }param; // 類成員信息 struct DexField { uint32_t delta_fieldIdx; uint32_t accessFlags; }; // 類方法信息 struct DexMethod { uint32_t delta_methodIdx; uint32_t accessFlags; uint32_t codeOff; }; struct DexClassDataHeader { uint32_t staticFieldsSize; uint32_t instanceFieldsSize; uint32_t directMethodsSize; uint32_t virtualMethodsSize; }; // 整個類的方法和成員信息 struct DexClassData { DexClassDataHeader header; DexField* staticFields; DexField* instanceFields; DexMethod* directMethods; DexMethod* virtualMethods; }; // 等待dump任務執行的等待定時器 void timer_thread(::sigval_t) { timer_flag=false; timer_delete(timerId); #ifdef LOGI LOG(INFO)<<"GOT IT time up"; #endif } // 讀取脫殼配置文件 void* ReadThread(void *arg){ FILE *fp = NULL; while (dexname[0]==0||dumppath[0]==0) { // 打開apk脫殼配置文件/data/dexname // 一些加固會檢測這個配置文件/data/dexname fp=fopen("/data/dexname", "r"); if (fp==NULL) { sleep(1); continue; } // 獲取被加固的dex文件內存加載的文件路徑 fgets(dexname, 99, fp); dexname[strlen(dexname)-1]=0; // 保存被加固dex文件的dump路徑 fgets(dumppath, 99, fp); dumppath[strlen(dumppath)-1]=0; 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; } // leb128數據的寫 void writeUnsignedLeb128(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; } } } // leb128數據的字節長度 int unsignedLeb128Size(uint32_t data) { int count = 0; do { data >>= 7; count++; } while (data != 0); return count; } // 獲取DexClassDataHeader結構體的各個成員的數據信息 void dexReadClassDataHeader(const uint8_t** pData, DexClassDataHeader *pHeader) { pHeader->staticFieldsSize = DecodeUnsignedLeb128(pData); pHeader->instanceFieldsSize = DecodeUnsignedLeb128(pData); pHeader->directMethodsSize = DecodeUnsignedLeb128(pData); pHeader->virtualMethodsSize = DecodeUnsignedLeb128(pData); } // 獲取DexClassData結構體DexFiled的數據信息 void dexReadClassDataField(const uint8_t** pData, DexField* pField) { pField->delta_fieldIdx = DecodeUnsignedLeb128(pData); pField->accessFlags = DecodeUnsignedLeb128(pData); } // 獲取DexClassData結構體DexMethod的數據信息 void dexReadClassDataMethod(const uint8_t** pData, DexMethod* pMethod) { pMethod->delta_methodIdx = DecodeUnsignedLeb128(pData); pMethod->accessFlags = DecodeUnsignedLeb128(pData); pMethod->codeOff = DecodeUnsignedLeb128(pData); } // 從內存dex文件中讀取指定DexFile::ClassDef對應的DexClassData即類成員和類方法描述數據到申請內存空間中 DexClassData* dexReadClassData(const uint8_t** pData) { DexClassDataHeader header; if (*pData == NULL) { return NULL; } // 獲取DexClassDataHeader結構體的各個成員的數據信息() dexReadClassDataHeader(pData,&header); // 計算DexClassData結構體及其全部DexFiled和全部DexMethod佔用的內存空間 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); if (result == NULL) { return NULL; } // 更新指針的位置,用於存放類靜態成員變量、類實例成員變量、類直接方法以及類虛擬方法 uint8_t* ptr = ((uint8_t*) result) + sizeof(DexClassData); result->header = header; 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; } // 獲取DexClassData中類靜態變量和類實例變量以及類直接方法和類虛方法的數據 // 存放到指定的申請內存空間中 for (uint32_t i = 0; i < header.staticFieldsSize; i++) { dexReadClassDataField(pData, &result->staticFields[i]); } for (uint32_t i = 0; i < header.instanceFieldsSize; i++) { dexReadClassDataField(pData, &result->instanceFields[i]); } for (uint32_t i = 0; i < header.directMethodsSize; i++) { dexReadClassDataMethod(pData, &result->directMethods[i]); } for (uint32_t i = 0; i < header.virtualMethodsSize; i++) { dexReadClassDataMethod(pData, &result->virtualMethods[i]); } return result; } // 將整個DexClassData所表示的類數據leb128編碼寫入到申請的內存空間中 uint8_t* dexEncodeClassData(DexClassData *pData, int& len) { len=0; // 獲取整個DexClassData所表示類數據的內存佔用大小 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].delta_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].delta_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].delta_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].delta_methodIdx); len+=unsignedLeb128Size(pData->virtualMethods[i].accessFlags); len+=unsignedLeb128Size(pData->virtualMethods[i].codeOff); } } // 根據整個DexClassData所示類數據的大小申請內存空間 uint8_t * store = (uint8_t *) malloc(len); if (!store) { // 申請內存失敗的狀況 return NULL; } uint8_t * result=store; // 將整個DexClassData所表示的類數據寫入到申請的內存空間中 writeUnsignedLeb128(&store,pData->header.staticFieldsSize); writeUnsignedLeb128(&store,pData->header.instanceFieldsSize); writeUnsignedLeb128(&store,pData->header.directMethodsSize); writeUnsignedLeb128(&store,pData->header.virtualMethodsSize); // 類靜態成員變量 if (pData->staticFields) { for (uint32_t i = 0; i < pData->header.staticFieldsSize; i++) { writeUnsignedLeb128(&store,pData->staticFields[i].delta_fieldIdx); writeUnsignedLeb128(&store,pData->staticFields[i].accessFlags); } } // 類實例變量 if (pData->instanceFields) { for (uint32_t i = 0; i < pData->header.instanceFieldsSize; i++) { writeUnsignedLeb128(&store,pData->instanceFields[i].delta_fieldIdx); writeUnsignedLeb128(&store,pData->instanceFields[i].accessFlags); } } // 類直接方法 if (pData->directMethods) { for (uint32_t i=0; i<pData->header.directMethodsSize; i++) { writeUnsignedLeb128(&store,pData->directMethods[i].delta_methodIdx); writeUnsignedLeb128(&store,pData->directMethods[i].accessFlags); writeUnsignedLeb128(&store,pData->directMethods[i].codeOff); } } // 類虛擬方法 if (pData->virtualMethods) { for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) { writeUnsignedLeb128(&store,pData->virtualMethods[i].delta_methodIdx); writeUnsignedLeb128(&store,pData->virtualMethods[i].accessFlags); writeUnsignedLeb128(&store,pData->virtualMethods[i].codeOff); } } free(pData); return result; } // 根據try...catch{}的處理語句計算DexFile::CodeItem結構體的結束地址 uint8_t* codeitem_end(const uint8_t **pData) { uint32_t num_of_list = DecodeUnsignedLeb128(pData); for (;num_of_list>0;num_of_list--) { int32_t num_of_handlers=DecodeSignedLeb128(pData); int num=num_of_handlers; if (num_of_handlers<=0) { num=-num_of_handlers; } for (; num > 0; num--) { DecodeUnsignedLeb128(pData); DecodeUnsignedLeb128(pData); } if (num_of_handlers<=0) { DecodeUnsignedLeb128(pData); } } return (uint8_t*)(*pData); } // 內存dump加固的dex文件的類數據信息 void* DumpClass(void *parament) { while (timer_flag) { sleep(5); } // 獲取當前art虛擬機的運行時Runtime Runtime* runtime = Runtime::Current(); // 附加到art虛擬機線程 runtime->AttachCurrentThread("ClassDumper", false, NULL,false); // 獲取當前art虛擬機的線程描述結構體Thread Thread *self=Thread::Current(); #ifdef LOGI LOG(INFO)<<"GOT IT DumpingClass"; #endif #ifdef LOGI // 獲取當前時間 uint64_t time = MilliTime(); LOG(INFO)<<"GOT IT begin "<<time<<" ms"; #endif // 當前Dex文件的內存鏡像OAT描述相關的結構體 const DexFile &dex_file=(*((struct arg*)parament)->dex_file); mirror::ClassLoader *class_loader=((struct arg*)parament)->class_loader; ClassLinker *cl = ((struct arg*)parament)->cl; char *path = new char[100]; strcpy(path, dumppath); // 拼接字符串獲得文件路徑 xxxx/classdef strcat(path, "classdef"); // 打開文件xxxx/classdef FILE *fp = fopen(path, "wb+"); strcpy(path, dumppath); // 拼接字符串獲得文件路徑xxxx/extra strcat(path, "extra"); // 打開文件xxxx/extra FILE *fp1 = fopen(path,"wb+"); uint32_t mask=0x3ffff; char padding=0; const char* header="Landroid"; bool pass=false; // 鎖 Locks::mutator_lock_->SharedLock(self); // 獲取當前dex文件的ClassDef的數量 size_t num_class_defs = dex_file.NumClassDefs(); // 獲取整個OAT文件的文件大小 uint32_t total_pointer = dex_file.Size(); uint32_t rec = total_pointer; // 獲取OAT文件內存4字節對齊後的文件大小 while (total_pointer&3) { total_pointer++; } // 獲取OAT文件4字節對齊須要填充'0'的數量 int inc = total_pointer - rec; // 獲取OAT文件裏dex文件的ClassDef結構體表Table的結束地址 uint32_t start = dex_file.class_defs_off_ + sizeof(DexFile::ClassDef)*num_class_defs; // 獲取OAT文件的文件大小即文件偏移 uint32_t end = dex_file.Size(); // 遍歷獲取OAT文件裏的dex文件的ClassDef並加載 for (size_t i = 0; i < num_class_defs; i++) { // 獲取OAT文件裏的dex文件的第i個ClassDef結構體 const DexFile::ClassDef &class_def = dex_file.GetClassDef(i); // 獲取ClassDef結構體描述的類的類簽名字符串,例如:Landroid/xxx/yyy; const char* descriptor = dex_file.GetClassDescriptor(class_def); // 描述dump的類是否須要額外的類數據信息 bool need_extra = false; // ART下dex文件的類內存加載後的描述結構體爲mirror::Class mirror::Class* klass=NULL; const byte * data=NULL; DexClassData* pData = NULL; #ifdef LOGI LOG(INFO) << "GOT IT " << descriptor; #endif // 過濾掉Android系統("Landroid")的類和沒有類數據的無效類(這兩中狀況不處理) if(!strncmp(header, descriptor, 8)||!class_def.class_data_off_) { pass = true; // 此種狀況,need_extra = false goto classdef; } // 查找指定類簽名描述的目標類 /** mirror::Class* **/klass = cl->FindClass(descriptor, class_loader); // 查找的目標類沒有找到的狀況 if (!klass) { #ifdef LOGI LOG(INFO)<<"GOT IT class Find Fail"; #endif // 異常處理 self->ClearException(); continue; } // 成功查找到指定類簽名描述的目標類 if(klass){ if(cl->EnsureInitialized(klass, true, true)){ #ifdef LOGI LOG(INFO)<<"GOT IT "<<descriptor<<" Initialized"; #endif }else{ self->ClearException(); } } // OAT文件裏dex文件的Class_Data數據存放在OAT文件的結尾或者Class_Def結構體表開始地址以前位置 if(class_def.class_data_off_<start || class_def.class_data_off_>end) { #ifdef LOGI LOG(INFO)<<"GOT IT class data off exceeding "<<descriptor; #endif // 須要額外的處理Class_Def need_extra=true; } // 獲取Class_Def描述的類的ClassData數據class_data_item data = dex_file.GetClassData(class_def); // 讀取OAT文件裏dex文件的類描述DexClassData描述的類成員和類方法的數據到申請的內存空間中 pData = dexReadClassData(&data); if (!pData) { // 失敗狀況 continue; } // 針對類直接方法的處理 if (pData->directMethods) { // 遍歷art下類的直接方法 for (uint32_t i = 0; i < pData->header.directMethodsSize; i++) { // art::mirror::ArtMethod是art下dex文件類通過內存加載後的描述結構體 // 獲取指定類的第i個直接類方法描述結構體art::mirror::ArtMethod art::mirror::ArtMethod *method = klass->GetDirectMethod(i); // 獲取類方法的函數屬性值AccessFlag uint32_t ac = (method->GetAccessFlags()) & mask; // 獲取類方法的字節碼偏移地址CodeItemOffset uint32_t codeitem_off = method->GetCodeItemOffset(); // 經過類方法的DexMethodIndex獲取到類方法的名稱字符串 uint32_t dex_method_idx = method->GetDexMethodIndex(); const char * name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); // 判斷dex文件中的類方法函數屬性值AccessFlag與實際類運行時art::mirror::ArtMethod中函數屬性值是否一致 if (ac != pData->directMethods[i].accessFlags) { #ifdef LOGI LOG(INFO)<<"GOT IT direct method AF changed "<<name; #endif // 騰訊加固有這種狀況,運行時native函數恢復爲java函數 need_extra=true; // 進行類方法函數屬性的更正(以運行時爲準) pData->directMethods[i].accessFlags=ac; } // 根據類方法實際運行時的codeitem_off與dex文件中的codeOff偏移地址的不一樣,進行類方法字節碼DexCode偏移地址的修正 if (codeitem_off != pData->directMethods[i].codeOff&&((codeitem_off>=start&&codeitem_off<=end)||codeitem_off==0)) { #ifdef LOGI LOG(INFO)<<"GOT IT direct method code changed "<<name; #endif need_extra=true; // 以類方法實際運行時的codeitem_off爲準,對dex文件中的類方法字節碼DexCode的偏移地址進行修正 pData->directMethods[i].codeOff=codeitem_off; } // 類方法的字節碼DexCode被存放在了OAT文件的文件末尾或者dex文件的ClassDef結構體表開始地址以前的位置 // 阿里加固出現過這種狀況 if ((codeitem_off<start || codeitem_off>end) && codeitem_off!=0) { #ifdef LOGI LOG(INFO)<<"GOT IT direct method code changed "<<name; #endif need_extra=true; // 統計將dex文件的類方法字節碼DexFile::CodeItem從OAT文件結尾的位置開始存放(注意內存4字節對齊) pData->directMethods[i].codeOff = total_pointer; // 獲取類方法字節碼描述結構體指針DexFile::CodeItem const DexFile::CodeItem * code = dex_file.GetCodeItem(codeitem_off); // 類方法字節碼描述結構體DexFile::CodeItem存放的起始地址 uint8_t *item=(uint8_t *) code; int code_item_len = 0; // 判斷類方法是否有try...catch{}語句 if (code->tries_size_) { // 獲取有try...catch{}語句狀況下,類方法的字節碼DexFile::CodeItem結構體的結束地址 const byte *handler_data = (const byte *)(DexFile::GetTryItems(*code, code->tries_size_)); uint8_t * tail = codeitem_end(&handler_data); // 有try...catch{}語句狀況下,類方法的字節碼DexFile::CodeItem結構體的字節大小 code_item_len = (int)(tail - item); }else{ // 無try...catch{}語句狀況下,類方法的字節碼DexFile::CodeItem結構體的字節大小 code_item_len = 16+code->insns_size_in_code_units_*2; } // 將不在正常dex文件偏移存放位置的類方法字節碼DexFile::CodeItem結構體的數據寫入到xxxx/extra文件中 fwrite(item, 1, code_item_len, fp1); fflush(fp1); // 更新存放類方法字節碼DexFile::CodeItem的文件偏移指針 total_pointer += code_item_len; // 進行內存4字節對齊的填充處理 while (total_pointer&3) { fwrite(&padding,1,1,fp1); fflush(fp1); total_pointer++; } #ifdef LOGI LOG(INFO)<<"GOT IT total_pointer "<<total_pointer; #endif } } } // 針對類虛方法的處理(和上面類直接方法的處理同樣) if (pData->virtualMethods) { // 遍歷類的虛方法 for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) { art::mirror::ArtMethod *method = klass->GetVirtualMethod(i); uint32_t ac = (method->GetAccessFlags()) & mask; uint32_t codeitem_off = method->GetCodeItemOffset(); uint32_t dex_method_idx = method->GetDexMethodIndex(); const char * name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); // 類方法函數屬性accessFlags的修復 if (ac != pData->virtualMethods[i].accessFlags) { #ifdef LOGI LOG(INFO)<<"GOT IT virtual method AF changed "<<name; #endif need_extra=true; pData->virtualMethods[i].accessFlags=ac; } // 類方法codeitem_off的修正,以類方法運行時的數據爲準 if (codeitem_off!=pData->virtualMethods[i].codeOff&&((codeitem_off>=start&&codeitem_off<=end)||codeitem_off==0)) { #ifdef LOGI LOG(INFO)<<"GOT IT virtual method code changed "<<name; #endif need_extra=true; pData->virtualMethods[i].codeOff=codeitem_off; } // 類方法的字節碼DexCode被存放在了OAT文件的文件末尾或者dex文件的ClassDef結構體表開始地址以前的位置 if ((codeitem_off<start || codeitem_off>end)&&codeitem_off!=0) { #ifdef LOGI LOG(INFO)<<"GOT IT virtual method code changed "<<name; #endif need_extra=true; // 統計將dex文件的類方法字節碼DexFile::CodeItem從OAT文件結尾的位置開始存放(注意內存4字節對齊) pData->virtualMethods[i].codeOff = total_pointer; const art::DexFile::CodeItem * code = dex_file.GetCodeItem(codeitem_off); uint8_t *item=(uint8_t *) code; int code_item_len = 0; // 判斷類方法是否有try...catch{}語句 if (code->tries_size_) { const byte *handler_data = (const byte *)(DexFile::GetTryItems(*code, code->tries_size_)); uint8_t * tail=codeitem_end(&handler_data); // 有try...catch{}語句狀況下,類方法的字節碼DexFile::CodeItem結構體的字節大小 code_item_len = (int)(tail-item); }else{ // 無try...catch{}語句狀況下,類方法的字節碼DexFile::CodeItem結構體的字節大小 code_item_len = 16+code->insns_size_in_code_units_*2; } // 將不在正常dex文件偏移存放位置的類方法字節碼DexFile::CodeItem結構體的數據寫入到xxxx/extra文件中 fwrite(item,1,code_item_len,fp1); fflush(fp1); // 更新存放類方法字節碼DexFile::CodeItem的文件偏移指針 total_pointer+=code_item_len; // 進行內存4字節對齊的填充處理 while (total_pointer&3) { fwrite(&padding,1,1,fp1); fflush(fp1); total_pointer++; } #ifdef LOGI LOG(INFO)<<"GOT IT total_pointer "<<total_pointer; #endif } } } // 上面是針對dex文件類方法的字節碼DexFile::CodeItem的修正處理並保存到xxxx/extra文件中 // 以及對dex文件的ClassDef對應的ClassData的數據修正處理(以運行時的類描述信息爲準) // 下面是針對dex文件的 classdef: DexFile::ClassDef *temp = (DexFile::ClassDef*) malloc(sizeof(DexFile::ClassDef)); if (!temp) { continue; } temp->class_idx_ = class_def.class_idx_; temp->pad1_=class_def.pad1_; temp->pad2_=class_def.pad2_; temp->access_flags_=class_def.access_flags_; temp->annotations_off_= class_def.annotations_off_; temp->class_data_off_=class_def.class_data_off_; temp->interfaces_off_=class_def.interfaces_off_; temp->source_file_idx_=class_def.source_file_idx_; temp->static_values_off_=class_def.static_values_off_; temp->superclass_idx_=class_def.superclass_idx_; if (pass) { // Android系統類和無效類的狀況處理 temp->class_data_off_=0; temp->annotations_off_=0; } uint8_t *p = (uint8_t *)temp; if (need_extra) { // dex文件的類DexClassData須要修正狀況 int class_data_len = 0; // 將DexClassData所表示的類數據pData進行leb128編碼寫入到申請的內存空間中 // class_data_len爲保存DexClassData進行leb128編碼後的數據長度 uint8_t *out = dexEncodeClassData(pData, class_data_len); if (!out) { continue; } // 修正DexFile::ClassDef中指向DexClassData的文件偏移指針 temp->class_data_off_ = total_pointer; #ifdef LOGI LOG(INFO)<<"GOT IT write extra"; #endif // 將正確修正後的dex文件的類DexClassData數據保存到xxxx/extra文件中 fwrite(out, 1, class_data_len, fp1); fflush(fp1); // 更新在xxxx/extra文件中存放DexClassData或者DexFile::CodeItem的文件偏移指針 total_pointer += class_data_len; // 內存4字節對齊的填充處理 while (total_pointer&3) { fwrite(&padding, 1, 1, fp1); fflush(fp1); total_pointer++; } #ifdef LOGI LOG(INFO)<<"GOT IT total_pointer "<<total_pointer; #endif free(out); } else { if (pData) { free(pData); } } #ifdef LOGI LOG(INFO)<<"GOT IT write classdef"; #endif // 將根據上面xxxx/extra文件中存放的DexClassData數據修正的DexFile::ClassDef結構體數據保存到xxxx/classdef文件中 fwrite(p, sizeof(DexFile::ClassDef), 1, fp); fflush(fp); free(temp); } // 釋放鎖 Locks::mutator_lock_->SharedUnlock(self); // 關閉文件 fclose(fp1); fclose(fp); #ifdef LOGI LOG(INFO)<<"GOT IT ClassDumped"; #endif self->SetState(kSleeping); // 取消對art虛擬機線程的附加 runtime->DetachCurrentThread(); // 須要脫殼的dex文件的內存dump已經所有完成,後面是dump後的dex文件重組處理 // 拼接字符串獲得文件路徑xxxx/whole.dex strcpy(path,dumppath); strcat(path,"whole.dex"); // 打開文件xxxx/whole.dex(用以存放dump重組後的dex文件) fp = fopen(path,"wb+"); // 設置文件指針在文件開頭 rewind(fp); int fd=-1; int r=-1; int len=0; char *addr=NULL; struct stat st; strcpy(path, dumppath); strcat(path,"part0"); // 打開文件xxxx/part0 fp1 = fopen(path,"rb"); char reg=0; // 讀取文件xxxx/part0中的數據內容保存到文件xxxx/whole.dex中 for (uint32_t i = 0; i < 16; i++) { fread(®, 1, 1, fp1); fwrite(®, 1, 1, fp); fflush(fp); } fclose(fp1); strcpy(path,dumppath); strcat(path,"part1"); // 打開文件xxxx/part1 fd = open(path, O_RDONLY, 0666); if (fd == -1) { return NULL; } // 獲取文件xxxx/part1的數據大小 r = fstat(fd, &st); if(r == -1){ close(fd); return NULL; } len = st.st_size; // 爲文件xxxx/part1建立內存映射進行文件的讀取操做 addr = (char*)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); // 將文件xxxx/part1的數據內容寫入保存到文件xxxx/whole.dex中 fwrite(addr, 1, len, fp); // 刷新文件流 fflush(fp); // 取消內存映射 munmap(addr,len); close(fd); #ifdef LOGI LOG(INFO)<<"GOT IT part1 over "; #endif strcpy(path, dumppath); strcat(path, "classdef"); // 打開文件xxxx/classdef fd = open(path, O_RDONLY, 0666); if (fd==-1) { return NULL; } // 獲取文件xxxx/classdef的數據大小 r = fstat(fd,&st); if(r==-1){ close(fd); return NULL; } len=st.st_size; // 爲文件xxxx/classdef建立內存映射實現文件的讀取操做 addr = (char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0); // 將文件xxxx/classdef的數據內容寫入到文件xxxx/whole.dex中 fwrite(addr,1,len,fp); fflush(fp); munmap(addr,len); close(fd); #ifdef LOGI LOG(INFO)<<"GOT IT classdef over "; #endif strcpy(path,dumppath); strcat(path,"data"); // 打開文件xxxx/data fd = open(path, O_RDONLY, 0666); if (fd==-1) { return NULL; } // 獲取文件xxxx/data的文件大小 r = fstat(fd, &st); if(r==-1){ close(fd); return NULL; } len=st.st_size; // 爲文件xxxx/data建立文件內存映射 addr=(char*)mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); // 將文件xxxx/data的數據內容寫入到文件xxxx/whole.dex中 fwrite(addr,1,len,fp); fflush(fp); munmap(addr,len); close(fd); #ifdef LOGI LOG(INFO)<<"GOT IT data over "; #endif // 對 xxxx/data 進行內存4字節對齊的'0'填充處理 while (inc>0) { fwrite(&padding, 1, 1, fp); fflush(fp); inc--; } strcpy(path, dumppath); strcat(path,"extra"); // 打開文件xxxx/extra fd = open(path,O_RDONLY,0666); if (fd==-1) { return NULL; } // 獲取文件xxxx/extra的文件大小 r = fstat(fd,&st); if(r == -1){ close(fd); return NULL; } len=st.st_size; // 爲文件xxxx/extra建立文件內存映射實現文件的讀取操做 addr = (char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0); // 將文件xxxx/extra的數據內容保存寫入到文件xxxx/whole.dex中 fwrite(addr, 1, len, fp); fflush(fp); munmap(addr,len); close(fd); /**** xxxx/part0 xxxx/part1 xxxx/classdef (dex文件的重組)--------> xxxx/whole.dex xxxx/data xxxx/extra *****/ #ifdef LOGI LOG(INFO)<<"GOT IT extra over "; #endif fclose(fp); delete path; #ifdef LOGI time = MilliTime(); LOG(INFO)<<"GOT IT end "<<time<<" ms"; #endif return NULL; } //-----------------------added end-----------------------// // art下的類加載函數 mirror::Class* ClassLinker::DefineClass(const char* descriptor, mirror::ClassLoader* class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { //-----------------------added begin-----------------------// int uid=::art::GetUid(); // compiler用來指定當前要建立的ART虛擬機是用來將DEX字節碼編譯成本地機器指令的 // 所以排除掉Runtime::Current()->IsCompiler()爲true的優化dex文件的art虛擬機狀況 // 參考:http://blog.csdn.net/Luoshengyang/article/details/39307813 if (Runtime::Current()->IsCompiler()) { goto there; } // 排除掉系統進程(uid == 0的狀況) if (uid) { if (readable) { // 鎖 pthread_mutex_lock(&read_mutex); if (readable) { readable=false; pthread_mutex_unlock(&read_mutex); pthread_t read_thread; // 建立線程,讀取脫殼配置文件/data/dexname的信息 // 獲取須要脫殼dex文件的加載路徑dexname以及存放脫殼後dex文件dump文件路徑dumppath pthread_create(&read_thread, NULL, ReadThread, NULL); }else{ pthread_mutex_unlock(&read_mutex); } } } // 排除掉uid==0的進程以及被dump的加固dex文件的內存加載路徑不能爲空 if(uid && strcmp(dexname,"")){ // dex_file.GetLocation().c_str()獲取到art下dex文件的加載路徑 // 經過加固dex文件的加載路徑判斷是不是須要脫殼的dex文件 char * res = strstr(dex_file.GetLocation().c_str(), dexname); if (res && flag) { pthread_mutex_lock(&mutex); if (flag) { flag=false; pthread_mutex_unlock(&mutex); char * temp = new char[100]; strcpy(temp, dumppath); // 拼接字符串獲得文件路徑 xxxx/part0 strcat(temp,"part0"); // 打開文件xxxx/part0 FILE *fp = fopen(temp, "wb+"); // ART下的OAT文件是一個私有的ELF文件格式 // 獲取OAT文件的內存映射的起始地址即dex優化後私有ELF文件的內存映射地址 const byte *addr = dex_file.Begin(); int length = 16; // 將OAT文件(即私有ELF文件的)前16字節數據保存到xxxx/part0中 for (int i = 0; i < 16; i++) { fwrite(addr+i, 1 ,1 ,fp); fflush(fp); } fclose(fp); strcpy(temp, dumppath); // 獲得路徑字符串xxxx/part1 strcat(temp,"part1"); // 打開文件xxxx/part1 fp = fopen(temp, "wb+"); // 內存地址指針移動到OAT文件即私有ELF文件的第17個字節的位置 addr = dex_file.Begin() + 16; // 獲取到OAT文件裏即私有ELF文件的第17個字節到dex文件class_defs_off_開始地址之間的數據長度 length = dex_file.class_defs_off_ - 16; // 將OAT文件裏即私有ELF文件的第17個字節到dex文件class_defs_off_開始地址的數據寫入到xxxx/part1中 fwrite(addr, 1, length, fp); // 刷新文件流 fflush(fp); fclose(fp); // 拼接獲得字符串xxxx/data strcpy(temp, dumppath); strcat(temp,"data"); // 打開文件xxxx/data fp = fopen(temp,"wb+"); // 將OAT文件裏的dex文件指針移動到dex文件的ClassDef結構體表Table的結尾位置 addr = dex_file.Begin()+dex_file.class_defs_off_+sizeof(DexFile::ClassDef)*dex_file.NumClassDefs(); // 獲取OAT文件裏dex文件的ClassDef結構體表Table的結尾位置到OAT文件的結尾數據長度 length=dex_file.Size()-dex_file.class_defs_off_-sizeof(DexFile::ClassDef)*dex_file.NumClassDefs(); // 將OAT文件裏dex文件的ClassDef結構體表Table的結束位置到OAT文件的結尾數據寫入到xxxx/data文件中 fwrite(addr, 1, length, fp); fflush(fp); fclose(fp); delete temp; // 當前dex文件所在的class_loader param.class_loader = class_loader; // 當前dex文件的內存加載的鏡像描述結構體 param.dex_file = &dex_file; // 當前dex文件所在的ClassLinker param.cl = this; pthread_t dumpthread; // 建立線程對須要脫殼dex的OAT文件裏的類數據進行內存dump處理 pthread_create(&dumpthread, NULL, DumpClass, (void*)¶m); }else{ pthread_mutex_unlock(&mutex); } } } //-----------------------added end-----------------------// there: Thread* self = Thread::Current(); SirtRef<mirror::Class> klass(self, NULL); // Load the class from the dex file. if (UNLIKELY(!init_done_)) { // finish up init of hand crafted class_roots_ if (strcmp(descriptor, "Ljava/lang/Object;") == 0) { klass.reset(GetClassRoot(kJavaLangObject)); } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) { klass.reset(GetClassRoot(kJavaLangClass)); } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) { klass.reset(GetClassRoot(kJavaLangString)); } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) { klass.reset(GetClassRoot(kJavaLangDexCache)); } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtField;") == 0) { klass.reset(GetClassRoot(kJavaLangReflectArtField)); } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) { klass.reset(GetClassRoot(kJavaLangReflectArtMethod)); } else { klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def))); } } else { klass.reset(AllocClass(self, SizeOfClass(dex_file, dex_class_def))); } if (UNLIKELY(klass.get() == NULL)) { CHECK(self->IsExceptionPending()); // Expect an OOME. return NULL; } klass->SetDexCache(FindDexCache(dex_file)); LoadClass(dex_file, dex_class_def, klass, class_loader); // Check for a pending exception during load if (self->IsExceptionPending()) { klass->SetStatus(mirror::Class::kStatusError, self); return NULL; } ObjectLock lock(self, klass.get()); klass->SetClinitThreadId(self->GetTid()); { // Add the newly loaded class to the loaded classes table. mirror::Class* existing = InsertClass(descriptor, klass.get(), Hash(descriptor)); if (existing != NULL) { // We failed to insert because we raced with another thread. Calling EnsureResolved may cause // this thread to block. return EnsureResolved(self, existing); } } // Finish loading (if necessary) by finding parents CHECK(!klass->IsLoaded()); if (!LoadSuperAndInterfaces(klass, dex_file)) { // Loading failed. klass->SetStatus(mirror::Class::kStatusError, self); return NULL; } CHECK(klass->IsLoaded()); // Link the class (if necessary) CHECK(!klass->IsResolved()); if (!LinkClass(klass, NULL, self)) { // Linking failed. klass->SetStatus(mirror::Class::kStatusError, self); return NULL; } CHECK(klass->IsResolved()); /* * We send CLASS_PREPARE events to the debugger from here. The * definition of "preparation" is creating the static fields for a * class and initializing them to the standard default values, but not * executing any code (that comes later, during "initialization"). * * We did the static preparation in LinkClass. * * The class has been prepared and resolved but possibly not yet verified * at this point. */ Dbg::PostClassPrepare(klass.get()); return klass.get(); }