/*
    此为DexHunter实现的主要功能,进行内存dump,将class_def_items中dump出classdef和extra部分
*/
void* DumpClass(void *parament)
{
  while (timer_flag) {
      sleep(5);
  }   DvmDex* pDvmDex=((struct arg*)parament)->pDvmDex; //pDvmDex代表一个dex文件
  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");  //构造classdef文件路径 
  FILE *fp = fopen(path, "wb+");   strcpy(path,dumppath);
  strcat(path,"extra"); //构造extra文件路径 
  FILE *fp1 = fopen(path,"wb+");   uint32_t mask=0x3ffff;
  char padding=0;
  const char* header="Landroid";
  unsigned int num_class_defs=pDexFile->pHeader->classDefsSize; //dex文件的Header域,class_defs_size,标示了class_def域有几个class_def_item
  uint32_t total_pointer = mem->length-uint32_t(pDexFile->baseAddr-(const u1*)mem->addr);
  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;
  uint32_t end = (uint32_t)((const u1*)mem->addr+mem->length-pDexFile->baseAddr);   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);
      const char *descriptor = dexGetClassDescriptor(pDvmDex->pDexFile,pClassDef);       if(!strncmp(header,descriptor,8)||!pClassDef->classDataOff)
      {
          pass=true;
          goto classdef;
      }       clazz = dvmDefineClass(pDvmDex, descriptor, loader);  //First Step:class加载       if (!clazz) {
         continue;
      }       ALOGI("GOT IT class: %s",descriptor);       if (!dvmIsClassInitialized(clazz)) {  //Second Step:class初始化,遍历所有类进行初始化
          if(dvmInitClass(clazz)){  //与dvmIsClassInitialized()函数共同完成初始化
              ALOGI("GOT IT init: %s",descriptor);
          }
      }
           
      if(pClassDef->classDataOff<start || pClassDef->classDataOff>end)
      {
          need_extra=true;  //是不是需要extra这一块,当存在class_data_off不在dex范围内时,就需要
      }       data=dexGetClassData(pDexFile, pClassDef);
      pData = ReadClassData(&data);       if (!pData) {
          continue;
      }       if (pData->directMethods) {
          for (uint32_t i=0; i<pData->header.directMethodsSize; i++) {
              Method *method = &(clazz->directMethods[i]);
              uint32_t ac = (method->accessFlags) & mask;               ALOGI("GOT IT direct method name %s.%s",descriptor,method->name);               if (!method->insns||ac&ACC_NATIVE) {
                  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)
              {
                  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)) {
                  ALOGI("GOT IT method code");
                  need_extra=true;
                  pData->directMethods[i].codeOff=codeitem_off;
              }               if ((codeitem_off<start || codeitem_off>end) && codeitem_off!=0) {
                  //如果code_item_off不在dex文件范围内,则写入extra; fp1为extra的句柄
                  //这里使用的是slider.pptx,中的第二种方案,见p42
                  need_extra=true;
                  pData->directMethods[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++;
                  }
              }
          }
      }       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;
           fwrite(out,1,class_data_len,fp1);
           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);
       fflush(fp);
  }   fclose(fp1);
  fclose(fp);
    //目前已经准备好了part1,classdef,data和extra 4部分文件
  strcpy(path,dumppath);
  strcat(path,"whole.dex"); //组合4部分,并写入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----------------------//

安卓 dex 通用脱壳技术研究(三)的更多相关文章

  1. 安卓 dex 通用脱壳技术研究(一)

    注:以下4篇博文中,部分图片引用自DexHunter作者zyqqyz在slide.pptx中的图片,版本归原作者所有: 0x01 背景介绍 安卓 APP 的保护一般分为下列几个方面: JAVA/C代码 ...

  2. 安卓 dex 通用脱壳技术研究(二)

    0x03 DexHunter代码分析 DexHunter 实现中,只需要修改一处文件:dalvik\vm\native\dalvik_system_DexFile.cpp 下面是BeyondCompa ...

  3. 安卓 dex 通用脱壳技术研究(四)

    /*     当第一个类执行到此函数时,我们在dvmDefineClass执行之前,也就是第一个类加载之前     注入我们的dump代码:即DumpClass()函数 */ static void  ...

  4. 基于.net的分布式系统限流组件 C# DataGridView绑定List对象时,利用BindingList来实现增删查改 .net中ThreadPool与Task的认识总结 C# 排序技术研究与对比 基于.net的通用内存缓存模型组件 Scala学习笔记:重要语法特性

    基于.net的分布式系统限流组件   在互联网应用中,流量洪峰是常有的事情.在应对流量洪峰时,通用的处理模式一般有排队.限流,这样可以非常直接有效的保护系统,防止系统被打爆.另外,通过限流技术手段,可 ...

  5. 20145307陈俊达_安卓逆向分析_Xposed的hook技术研究

    20145307陈俊达_安卓逆向分析_Xposed的hook技术研究 引言 其实这份我早就想写了,xposed这个东西我在安卓SDK 4.4.4的时候就在玩了,root后安装架构,起初是为了实现一些屌 ...

  6. 【转】手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)

    1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理!   我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...

  7. 手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)

    1.引言 特别说明:本文内容仅用于即时通讯技术研究和学习之用,请勿用于非法用途.如本文内容有不妥之处,请联系JackJiang进行处理!   我司有关部门为了获取黑产群的动态,有同事潜伏在大量的黑产群 ...

  8. Ngnix技术研究系列2-基于Redis实现动态路由

    上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...

  9. Nginx技术研究系列2-基于Redis实现动态路由

    上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...

随机推荐

  1. EF - Database First 开发方式

    概述 Database First 又叫数据库优先的开发方式,是一种比较旧的开发方式,现在越来越多的企业已经不再使用此种开发方式. 当然,对于一些旧项目进行升级,在已经有了数据库的情况下,使用此种方式 ...

  2. JS 设置盒子div 跳转

    方式一 window.location.href=”url”; 在当前窗口跳转 方式二 window.open(‘url’) 在新窗口跳转 window.open(‘url’,’_self’) 在当前 ...

  3. C++ Leetcode Median of Two Sorted Arrays

    坚持每天刷一道题的小可爱还没有疯,依旧很可爱! 题目:There are two sorted arrays nums1 and nums2 of size m and n respectively. ...

  4. NOIP2012国王游戏(60分题解)

    题目描述 恰逢 H国国庆,国王邀请n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排成一排,国王站在队伍的最前面 ...

  5. java高级---->Serializable的过程分析

    本次讲解中我们在上次的基础上,深入的了解一下序列化的流程以及其中的原理.关于序列化的一些知识与使用,请参见我的另一篇博客:java基础---->Serializable的使用.好了,我们进行以下 ...

  6. oracle 11g创建数据库教程

    cd /oracle/app/oracle/product//dbhome_1/bin ./dbca 自定义用户表空间大小. 安装过程半个小时是需要的. 2.配置oracle系统用户环境变量 使用vi ...

  7. activity和fragment之前运行的生命周期

    1.activity生命周期 2.fragment的生命周期 3.对比图 4.测试代码 package com.goso.testapp; import android.app.Activity; i ...

  8. @NotNull, @NotEmpty和@NotBlank之间的区别是什么?

    首先是简要描述: [java] view plain copy@NotNull://CharSequence, Collection, Map 和 Array 对象不能是 null, 但可以是空集(s ...

  9. learning at command AT+CGSN

    AT command AT+CGSN [Purpose]        Learning how to get mobile module international Mobile Equipment ...

  10. QuickStart系列:docker部署之MongoDB

    MongoDB[1]  是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB[2]  是一个介于关系数据库和非关系数据库之间的产品, ...