美文网首页
虚拟机对于 Dex 文件的解析

虚拟机对于 Dex 文件的解析

作者: Wi1ls努力努力再努力 | 来源:发表于2019-05-30 22:58 被阅读0次

    数据结构

    以下基于 Android_4.0.4源码进行分析。

    先丢一张虚拟机用到的数据结构。我们的起点在
    native private static int openDexFile(String sourceName, String outputName, int flags) throws IOException @ DexFile.java

    //@dalvik/vm/native/dalvik_system_DexFile.cpp
    static void Dalvik_dalvik_system_DexFile_openFile(const u4* args, JValue* pResult){
      RawDexFile* pJarFile;
      ...
      dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false);
      ...
    }
    
    //@dalvik/vm/RawDexFile.cpp
    int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
      RawDexFile** ppRawDexFile, bool isBootstrap){
      DvmDex* pDvmDex = NULL;
      ...
      //@dalvik/vm/analysis/DexPrepare
      //优化
      result = dvmOptimizeDexFile(optFd, dexOffset, fileSize, fileName, modTime, adler32, isBootstrap);
      ...
      //@dalvik/vm/DvmDex.cpp
      dvmDexFileOpenFromFd(optFd, &pDvmDex);
    }
    
    @dalvik/vm/DvmDex.cpp
    int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex){
      DvmDex* pDvmDex;
      DexFile* pDexFile;
      ...
      //重点 1,用以解析 Dex 文件,返回一个对应的 DexFile 数据结构
      //@dalvik/libdex/DexFile.cpp
      pDexFile = dexFileParse((u1*)memMap.addr, memMap.length, parseFlags);
      // 重点 2,根据 DexFile 填充 DvmDex 信息
      pDvmDex = allocateAuxStructures(pDexFile);
    }
    

    重点 1

    //@dalvik/libdex/DexFile.cpp
    DexFile* dexFileParse(const u1*data, size_t length, int flags){
      DexFile* pDexFile = NULL;
      const DexHeader* pHeader;
      ...
      //分配内存
      pDexFile = (DexFile*) malloc(sizeof(DexFile));
      ...
      dexParseOptData(data, length, pDexFile);
      ...
      //通过 Dex 文件信息,填充 DexFile 的信息
      dexFileSetupBasicPointers(pDexFile, data);
      ...
    }
    
    //data 是打开的 Dex 文件在内存中的地址,而 DexHeader 中的形如 stringIdsOff 都是相对于文件首地址的偏移,因此在 DexFile 中的 pStringIds、pTypeIds 保存的是 Dex 文件中stringIds,TypeIds 等信息在内存中的实际地址。
    void dexFileSetupBasicPointers(DexFile* pDexFile, const u1* data){
        DexHeader *pHeader = (DexHeader*) data;
    
        pDexFile->baseAddr = data;
        pDexFile->pHeader = pHeader;
        pDexFile->pStringIds = (const DexStringId*) (data + pHeader->stringIdsOff);
        pDexFile->pTypeIds = (const DexTypeId*) (data + pHeader->typeIdsOff);
        pDexFile->pFieldIds = (const DexFieldId*) (data + pHeader->fieldIdsOff);
        pDexFile->pMethodIds = (const DexMethodId*) (data + pHeader->methodIdsOff);
        pDexFile->pProtoIds = (const DexProtoId*) (data + pHeader->protoIdsOff);
        pDexFile->pClassDefs = (const DexClassDef*) (data + pHeader->classDefsOff);
        pDexFile->pLinkData = (const DexLink*) (data + pHeader->linkOff);
    }
    
    

    重点 2
    @DvmDex.cpp
    //根据 DexFile 的信息填充 DvmDex
    static DvmDex* allocateAuxStructres(DexFile* pDexFile){
    DvmDex* pDvmDex;
    const DexHeader* pHeader;
    u4 stringCount, classCount, methodCount, fileCount;

    pDvmDex = (DvmDex*) calloc(1, sizeof(DvmDex));
    pDvmDex->pDexFile = pDexFile;
    pDvmDex->pHeader = pDexFile->pHeader;

    pHeader = pDvmDex->pHeader;

    stringCount = pHeader->stringIdsSize;
    classCount = pHeader->typeIdsSize;
    methodCount = pHeader->methodIdsSize;
    filedCount = pHeader->fileIdsSize;
    //根据实际的数量分配内存
    pDvmDex->pResStrings = (struct StringObject) calloc(stringCount, sizeof(struct stringObject));
    pDvmDex->pResClasses = (struct ClassObject
    ) calloc(ClassObject, sizeof(struct ClassObject));
    pDvmDex->pResMethods = (struct Method) calloc(methodCount, sizeof(struct Method));
    pDvmDex->pResFilds = (struct Field
    ) calloc(fieldCount, sizeof(struct Field));
    ...
    pDvmDex->pInterfaceCache = dvmAllocAtomicCache(DEX_INTERFACE_CACHE_SIZE);
    }


    *从上面看出来,DvmDex 包含 DexFile,DexFile 包含 DexHeader。通过解析 DexHeader,将常量池,方法区,字段等信息在内存的首地址存入 DexFile;然后通过 DexFile 的信息在 DvmDex 中分配合适的内存。于是 Dex 文件便初步解析完成了,并且保存在了内存。在进行类加载的时候,一个类的信息在内存中以 ClassObject 的结构保存。同时在 DexFile 中有一个 ClassLookup* pClassLookup 作为一个哈希表作为缓存保存已经加载了的类。

    另外native private static int openDexFile(String sourceName, String outputName, int flags)的返回值是一个 int。明显这个 int 是对应 native 中一个对象的句柄。那么来看 Dalvik_dalvik_system_DexFile_openDexFile()@dalvik_system_DexFile.cpp 中的返回值是 DexOrJar。
    于是在 DexFile 中的 cookie 保存的便是这个 DexOrJar 的地址。


    https://github.com/Wi1ls/DexParse


    opt

    相关文章

      网友评论

          本文标题:虚拟机对于 Dex 文件的解析

          本文链接:https://www.haomeiwen.com/subject/yibbtctx.html