zoukankan      html  css  js  c++  java
  • DexHunter在ART虚拟机模式下的脱壳原理分析

    本文博客地址: http://blog.csdn.net/qq1084283172/article/details/78494620


    DexHunter脱壳工具在Dalvik虚拟机模式下的脱壳原理分析,在前面的博客中已经提到了,但是自我感觉分析和理解的还不够透彻,后面又对DexHunter脱壳工具的源码再阅读了几遍,总算是把DexHunter脱壳工具在Dalvik虚拟机模式下和ART虚拟机模式下的脱壳原理理解清楚了。关于DexHunter脱壳工具在Dalvik虚拟机模式下的脱壳原理分析,已经准备了一篇博客想详细和深入的讲一讲,一直搁置了没有完成;本来还计划把DexHunter脱壳工具在ART虚拟机模式下的脱壳原理也详细说一说,看来是不可能了。有关Android加固脱壳和Hook的好几个源码工程都看的差不多了,因为各种事情和状态不好,懒得动笔了。


    在理解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
    ’
    	  uint8_t version_[4];	// OAT文件版本号,目前的值等于‘007、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();
    }                                                                                                                          
    
    

  • 相关阅读:
    序列、元组、列表(基本的增、删、改、查)
    Python基础运算符(算数、比较、赋值、逻辑、成员)
    2015年9月14日记事
    2014年3月31日梦
    华为S5700系列交换机配置文件导出、导入
    C语言单链表简单实现(简单程序复杂化)
    北邮《大学英语2》第三次阶段作业带答案
    C++走向远洋——30(六周,项目一1.0)
    C++走向远洋——29(长方柱类)
    C++走向远洋——28(项目三,时间类,2)
  • 原文地址:https://www.cnblogs.com/csnd/p/11800598.html
Copyright © 2011-2022 走看看