1. 程式人生 > >DexHunter脫殼神器分析

DexHunter脫殼神器分析

    0x00

    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,extra
        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;
}

void ReadClassDataHeader(const uint8_t** pData,
        DexClassDataHeader *pHeader) {
    pHeader->staticFieldsSize = readUnsignedLeb128(pData);
    pHeader->instanceFieldsSize = readUnsignedLeb128(pData);
    pHeader->directMethodsSize = readUnsignedLeb128(pData);
    pHeader->virtualMethodsSize = readUnsignedLeb128(pData);
}

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);
}

DexClassData* ReadClassData(const uint8_t** pData) {

    DexClassDataHeader header;

    if (*pData == NULL) {
        return NULL;
    }

    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);

    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;
    }

    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]);
    }

    return result;
}

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;
        }
    }
}

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);
}

void* DumpClass(void *parament)
{
  while (timer_flag) {
      sleep(5);
  }
  
  DvmDex* pDvmDex=((struct arg*)parament)->pDvmDex;
  Object *loader=((struct arg*)parament)->loader;
  DexFile* pDexFile=pDvmDex->pDexFile;
  MemMapping * mem=&pDvmDex->memMap;

  u4 time=dvmGetRelativeTimeMsec();
  ALOGI("GOT IT begin: %d ms",time);

  char *path = new char[100];
  strcpy(path,dumppath);
  strcat(path,"classdef");
  FILE *fp = fopen(path, "wb+");//fp指向classdef檔案

  strcpy(path,dumppath);
  strcat(path,"extra");
  FILE *fp1 = fopen(path,"wb+");//fp1指向extra檔案

  uint32_t mask=0x3ffff;
  char padding=0;
  const char* header="Landroid";
  unsigned int num_class_defs=pDexFile->pHeader->classDefsSize;//class_def的數量
  uint32_t total_pointer = mem->length-uint32_t(pDexFile->baseAddr-(const u1*)mem->addr);//末尾地址相對DexHeader頭部的偏移地址
  uint32_t rec=total_pointer;

  while (total_pointer&3) {
      total_pointer++;//對齊
  }

  int inc=total_pointer-rec;
  uint32_t start = pDexFile->pHeader->classDefsOff+sizeof(DexClassDef)*num_class_defs;//若干個class_def_item之後的地址相對於DexHeader頭部的偏移地址
  uint32_t end = (uint32_t)((const u1*)mem->addr+mem->length-pDexFile->baseAddr);//末尾地址相對DexHeader頭部的偏移地址

  for (size_t i=0;i<num_class_defs;i++)//遍歷class_def_item
  {
      bool need_extra=false;
      ClassObject * clazz=NULL;
      const u1* data=NULL;
      DexClassData* pData = NULL;
      bool pass=false;
      const DexClassDef *pClassDef = dexGetClassDef(pDvmDex->pDexFile, i);//找到了對應的class_def_item,如圖2
      const char *descriptor = dexGetClassDescriptor(pDvmDex->pDexFile,pClassDef);

      if(!strncmp(header,descriptor,8)||!pClassDef->classDataOff)
      {
          pass=true;
          goto classdef;
      }

      clazz = dvmDefineClass(pDvmDex, descriptor, loader);//前面說過,脫殼程式能夠執行的很重要的原理是,這裡生成的ClassObject結構體中的變數都是有效的。

      if (!clazz) {
         continue;
      }

      ALOGI("GOT IT class: %s",descriptor);

      if (!dvmIsClassInitialized(clazz)) {
          if(dvmInitClass(clazz)){
              ALOGI("GOT IT init: %s",descriptor);
          }
      }
           
      if(pClassDef->classDataOff<start || pClassDef->classDataOff>end)//如果classDataOff的偏移落在範圍外,那就需要生成extra部分,詳解後面的程式碼
      {
          need_extra=true;
      }

      data=dexGetClassData(pDexFile,pClassDef);//通過class_def獲取class_data_item,詳解圖2
      pData = ReadClassData(&data);//讀取現在記憶體中的值,形成了DexClassData結構體pData,注意此時pData中的變數可能是錯誤的,很簡單的一個例子就是http://blog.csdn.net/jltxgcy/article/details/50581259,參考這篇文章

      if (!pData) {
          continue;
      }

      if (pData->directMethods) {
          for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
              Method *method = &(clazz->directMethods[i]);//此時獲取Method結構體method裡面的變數是正確的
              uint32_t ac = (method->accessFlags) & mask;//正確的accessFlags

              ALOGI("GOT IT direct method name %s.%s",descriptor,method->name);

              if (!method->insns||ac&ACC_NATIVE) {//正確的insns沒有指令,所以要調整
                  if (pData->directMethods[i].codeOff) {
                      need_extra = true;
                      pData->directMethods[i].accessFlags=ac;
                      pData->directMethods[i].codeOff=0;
                  }
                  continue;
              }

              u4 codeitem_off = u4((const u1*)method->insns-16-pDexFile->baseAddr);//獲取正確的指令偏移

              if (ac != pData->directMethods[i].accessFlags)//當前的accessFlag和正確的accessFlag不一致,所以要調整
              {
                  ALOGI("GOT IT method ac");
                  need_extra=true;
                  pData->directMethods[i].accessFlags=ac;
              }

              if (codeitem_off!=pData->directMethods[i].codeOff&&((codeitem_off>=start&&codeitem_off<=end)||codeitem_off==0)) {//如果正確的codeitem_off不等於現在的codeitem_off,且正確的codeitem_off在範圍內,則需要調整
                  ALOGI("GOT IT method code");
                  need_extra=true;
                  pData->directMethods[i].codeOff=codeitem_off;
              }

              if ((codeitem_off<start || codeitem_off>end) && codeitem_off!=0) {//在http://blog.csdn.net/jltxgcy/article/details/50581259,所屬的情況在這個判斷中,真是的codeitem_off在範圍(start--end)外。
                  need_extra=true;
                  pData->directMethods[i].codeOff = total_pointer;//讓codeOff指向dex結尾的偏移
                  DexCode *code = (DexCode*)((const u1*)method->insns-16);//正確的DexCode
                  uint8_t *item=(uint8_t *) code;
                  int code_item_len = 0;
                  if (code->triesSize) {
                      const u1 * handler_data = dexGetCatchHandlerData(code);
                      const u1** phandler=(const u1**)&handler_data;
                      uint8_t * tail=codeitem_end(phandler);
                      code_item_len = (int)(tail-item);
                  }else{
                      code_item_len = 16+code->insnsSize*2;//正確的DexCode的大小
                  }

                  ALOGI("GOT IT method code changed");

                  fwrite(item,1,code_item_len,fp1);//把DexCode寫入extra中
                  fflush(fp1);
                  total_pointer+=code_item_len;
                  while (total_pointer&3) {
                      fwrite(&padding,1,1,fp1);
                      fflush(fp1);
                      total_pointer++;
                  }
              }
          }
      }

      if (pData->virtualMethods) {//同理
          for (uint32_t i=0; i<pData->header.virtualMethodsSize; i++) {
              Method *method = &(clazz->virtualMethods[i]);
              uint32_t ac = (method->accessFlags) & mask;

              ALOGI("GOT IT virtual method name %s.%s",descriptor,method->name);

              if (!method->insns||ac&ACC_NATIVE) {
                  if (pData->virtualMethods[i].codeOff) {
                      need_extra = true;
                      pData->virtualMethods[i].accessFlags=ac;
                      pData->virtualMethods[i].codeOff=0;
                  }
                  continue;
              }

              u4 codeitem_off = u4((const u1 *)method->insns - 16 - pDexFile->baseAddr);

              if (ac != pData->virtualMethods[i].accessFlags)
              {
                  ALOGI("GOT IT method ac");
                  need_extra=true;
                  pData->virtualMethods[i].accessFlags=ac;
              }

              if (codeitem_off!=pData->virtualMethods[i].codeOff&&((codeitem_off>=start&&codeitem_off<=end)||codeitem_off==0)) {
                  ALOGI("GOT IT method code");
                  need_extra=true;
                  pData->virtualMethods[i].codeOff=codeitem_off;
              }

              if ((codeitem_off<start || codeitem_off>end)&&codeitem_off!=0) {
                  need_extra=true;
                  pData->virtualMethods[i].codeOff = total_pointer;
                  DexCode *code = (DexCode*)((const u1*)method->insns-16);
                  uint8_t *item=(uint8_t *) code;
                  int code_item_len = 0;
                  if (code->triesSize) {
                      const u1 *handler_data = dexGetCatchHandlerData(code);
                      const u1** phandler=(const u1**)&handler_data;
                      uint8_t * tail=codeitem_end(phandler);
                      code_item_len = (int)(tail-item);
                  }else{
                      code_item_len = 16+code->insnsSize*2;
                  }

                  ALOGI("GOT IT method code changed");

                  fwrite(item,1,code_item_len,fp1);
                  fflush(fp1);
                  total_pointer+=code_item_len;
                  while (total_pointer&3) {
                      fwrite(&padding,1,1,fp1);
                      fflush(fp1);
                      total_pointer++;
                  }
              }
          }
      }

classdef:
       DexClassDef temp=*pClassDef;
       uint8_t *p = (uint8_t *)&temp;

       if (need_extra) {
           ALOGI("GOT IT classdata before");
           int class_data_len = 0;
           uint8_t *out = EncodeClassData(pData,class_data_len);
           if (!out) {
               continue;
           }
           temp.classDataOff = total_pointer;//class_def的classDataOff指向了新生成的class_data_item
           fwrite(out,1,class_data_len,fp1);//將這個class_data_item寫入extra,此class_data_item中的codeOff已經改變了
           fflush(fp1);
           total_pointer+=class_data_len;
           while (total_pointer&3) {
               fwrite(&padding,1,1,fp1);
               fflush(fp1);
               total_pointer++;
           }
           free(out);
           ALOGI("GOT IT classdata written");
       }else{
           if (pData) {
               free(pData);
           }
       }

       if (pass) {
           temp.classDataOff=0;
           temp.annotationsOff=0;
       }

       ALOGI("GOT IT classdef");
       fwrite(p, sizeof(DexClassDef), 1, fp);//將class_def入classdef檔案,改class_def中的classDataOff已經改變了
       fflush(fp);
  }

  fclose(fp1);
  fclose(fp);
  //最後執行完畢後,把四個檔案按照先後順序合併在一起,依次是part1,classdef,data,extra,最後生成dex就是正確的dex
  strcpy(path,dumppath);
  strcat(path,"whole.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,"part1");

  fd=open(path,O_RDONLY,0666);
  if (fd==-1) {
      return NULL;
  }

  r=fstat(fd,&st);  
  if(r==-1){  
      close(fd);  
      return NULL;
  }

  len=st.st_size;
  addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
  fwrite(addr,1,len,fp);
  fflush(fp);
  munmap(addr,len);
  close(fd);

  strcpy(path,dumppath);
  strcat(path,"classdef");

  fd=open(path,O_RDONLY,0666);
  if (fd==-1) {
      return NULL;
  }

  r=fstat(fd,&st);  
  if(r==-1){  
      close(fd);  
      return NULL;
  }

  len=st.st_size;
  addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
  fwrite(addr,1,len,fp);
  fflush(fp);
  munmap(addr,len);
  close(fd);

  strcpy(path,dumppath);
  strcat(path,"data");

  fd=open(path,O_RDONLY,0666);
  if (fd==-1) {
      return NULL;
  }

  r=fstat(fd,&st);  
  if(r==-1){  
      close(fd);  
      return NULL;
  }

  len=st.st_size;
  addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
  fwrite(addr,1,len,fp);
  fflush(fp);
  munmap(addr,len);
  close(fd);

  while (inc>0) {
      fwrite(&padding,1,1,fp);
      fflush(fp);
      inc--;
  }

  strcpy(path,dumppath);
  strcat(path,"extra");

  fd=open(path,O_RDONLY,0666);
  if (fd==-1) {
      return NULL;
  }

  r=fstat(fd,&st);  
  if(r==-1){  
      close(fd);  
      return NULL;
  }

  len=st.st_size;
  addr=(char*)mmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);
  fwrite(addr,1,len,fp);
  fflush(fp);
  munmap(addr,len);
  close(fd);

  fclose(fp);
  delete path;

  time=dvmGetRelativeTimeMsec();
  ALOGI("GOT IT end: %d ms",time);

  return NULL;
}
//------------------------added end----------------------//

static void Dalvik_dalvik_system_DexFile_defineClassNative(const u4* args,
    JValue* pResult)
{
    StringObject* nameObj = (StringObject*) args[0];
    Object* loader = (Object*) args[1];
    int cookie = args[2];
    ClassObject* clazz = NULL;
    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
    DvmDex* pDvmDex;
    char* name;
    char* descriptor;

    name = dvmCreateCstrFromString(nameObj);
    descriptor = dvmDotToDescriptor(name);
    ALOGV("--- Explicit class load '%s' l=%p c=0x%08x",
        descriptor, loader, cookie);
    free(name);

    if (!validateCookie(cookie))
        RETURN_VOID();

    if (pDexOrJar->isDex)
        pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);
    else
        pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile);

    /* once we load something, we can't unmap the storage */
    pDexOrJar->okayToFree = false;

//------------------------added begin----------------------//
    int uid=getuid();

    if (uid) {
        if (readable) {
            pthread_mutex_lock(&read_mutex);
            if (readable) {//只執行一次,避免多次執行
                readable=false;
                pthread_mutex_unlock(&read_mutex);

                pthread_t read_thread;
                pthread_create(&read_thread, NULL, ReadThread, NULL);//在新的執行緒中執行ReadThread,ReadThread在上面的程式碼中

            }else{
                pthread_mutex_unlock(&read_mutex);
            }
        }
    }

    if(uid&&strcmp(dexname,"")){
        char * res=strstr(pDexOrJar->fileName, dexname);//這個是dexname的用途,用來比較,只有匹配的dex才會執行後面的程式碼
        if (res&&flag) {
            pthread_mutex_lock(&mutex);
            if (flag) {
                flag = false;
                pthread_mutex_unlock(&mutex);
 
                DexFile* pDexFile=pDvmDex->pDexFile;
                MemMapping * mem=&pDvmDex->memMap;

                char * temp=new char[100];
                strcpy(temp,dumppath);
                strcat(temp,"part1");
                FILE *fp = fopen(temp, "wb+");
                const u1 *addr = (const u1*)mem->addr;
                int length=int(pDexFile->baseAddr+pDexFile->pHeader->classDefsOff-addr);//class_defs之前的內容的長度,mem->addr,和baseAddr是理解這個長度的關鍵,在程式碼前的紅字部分有說明和圖解。
                fwrite(addr,1,length,fp);//class_defs之前的內容寫入part1
                fflush(fp);
                fclose(fp);

                strcpy(temp,dumppath);
                strcat(temp,"data");
                fp = fopen(temp, "wb+");
                addr = pDexFile->baseAddr+pDexFile->pHeader->classDefsOff+sizeof(DexClassDef)*pDexFile->pHeader->classDefsSize;
                length=int((const u1*)mem->addr+mem->length-addr);//class_defs之後的內容的長度
                fwrite(addr,1,length,fp);//class_defs之後的內容寫入data中
                fflush(fp);
                fclose(fp);
                delete temp;

                param.loader=loader;
                param.pDvmDex=pDvmDex;

                pthread_t dumpthread;
                dvmCreateInternalThread(&dumpthread,"ClassDumper",DumpClass,(void*)param);//在新的執行緒中執行DumpClass,引數是param,這個函式的實現在前面的程式碼中                             

            }else{
                pthread_mutex_unlock(&mutex);
            }
        }
    }
//------------------------added end----------------------//

    clazz = dvmDefineClass(pDvmDex, descriptor, loader);
    Thread* self = dvmThreadSelf();
    if (dvmCheckException(self)) {
        /*
         * If we threw a "class not found" exception, stifle it, since the
         * contract in the higher method says we simply return null if
         * the class is not found.
         */
        Object* excep = dvmGetException(self);
        if (strcmp(excep->clazz->descriptor,
                   "Ljava/lang/ClassNotFoundException;") == 0 ||
            strcmp(excep->clazz->descriptor,
                   "Ljava/lang/NoClassDefFoundError;") == 0)
        {
            dvmClearException(self);
        }
        clazz = NULL;
    }

    free(descriptor);
    RETURN_PTR(clazz);
}

    0x04

    如果是執行時動態修復dex這篇文章執行的DynamicDex.apk,上面的程式碼解釋也著重分析了,解析後會形成下圖的結構(正確的dex)。

     

    第一部分是part1,第二部分是classdef,第三部分是data,第四部分是extra。

    第二部分的其中一個class_def_item中的classDataOff指向了extra中class_data_item。

    extra中的class_data_item中的codeOff指向了extra中DexCode。