DexHunter在ART虛擬機模式下的脫殼原理分析

本文博客地址: 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(&reg, 1, 1, fp1);
      fwrite(&reg, 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*)&param);

         }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();
}
相關文章
相關標籤/搜索