【Android逆向】脱壳项目frida_dump 原理分析

脱dex核心文件dump_dex.js

核心函数

function dump_dex() {
    var libart = Process.findModuleByName("libart.so");
    var addr_DefineClass = null;
    var symbols = libart.enumerateSymbols();
    for (var index = 0; index < symbols.length; index++) {
        var symbol = symbols[index];
        var symbol_name = symbol.name;
        //这个DefineClass的函数签名是Android9的
        //_ZN3art11ClassLinker11DefineClassEPNS_6ThreadEPKcmNS_6HandleINS_6mirror11ClassLoaderEEERKNS_7DexFileERKNS9_8ClassDefE
        if (symbol_name.indexOf("ClassLinker") >= 0 &&
            symbol_name.indexOf("DefineClass") >= 0 &&
            symbol_name.indexOf("Thread") >= 0 &&
            symbol_name.indexOf("DexFile") >= 0) {
            console.log(symbol_name, symbol.address);
            addr_DefineClass = symbol.address;
        }
    }
    var dex_maps = {};
    var dex_count = 1;

    console.log("[DefineClass:]", addr_DefineClass);
    if (addr_DefineClass) {
        Interceptor.attach(addr_DefineClass, {
            onEnter: function(args) {
                var dex_file = args[5];
                //ptr(dex_file).add(Process.pointerSize) is "const uint8_t* const begin_;"
                //ptr(dex_file).add(Process.pointerSize + Process.pointerSize) is "const size_t size_;"
                var base = ptr(dex_file).add(Process.pointerSize).readPointer();
                var size = ptr(dex_file).add(Process.pointerSize + Process.pointerSize).readUInt();

                if (dex_maps[base] == undefined) {
                    dex_maps[base] = size;
                    var magic = ptr(base).readCString();
                    if (magic.indexOf("dex") == 0) {

                        var process_name = get_self_process_name();
                        if (process_name != "-1") {
                            var dex_dir_path = "/data/data/" + process_name + "/files/dump_dex_" + process_name;
                            mkdir(dex_dir_path);
                            var dex_path = dex_dir_path + "/class" + (dex_count == 1 ? "" : dex_count) + ".dex";
                            console.log("[find dex]:", dex_path);
                            var fd = new File(dex_path, "wb");
                            if (fd && fd != null) {
                                dex_count++;
                                var dex_buffer = ptr(base).readByteArray(size);
                                fd.write(dex_buffer);
                                fd.flush();
                                fd.close();
                                console.log("[dump dex]:", dex_path);

                            }
                        }
                    }
                }
            },
            onLeave: function(retval) {}
        });
    }
}

原理是:通过hook libart ,然后开始枚举符号表,根据符号名称找到DefineClass函数,通过DefineClass的地址来得到它的入参中的DexFile对象
# /art/runtime/class_linker.cc

 mirror::Class* ClassLinker::DefineClass(Thread* self,
                                          const char* descriptor,
                                          size_t hash,
                                          Handle<mirror::ClassLoader> class_loader,
                                          const DexFile& dex_file,
                                         const DexFile::ClassDef& dex_class_def) {

......
}
DexFile 数据结构为
 struct DexFile {
      /* directly-mapped "opt" header */
      const DexOptHeader* pOptHeader;
  
      /* pointers to directly-mapped structs and arrays in base DEX */
      const DexHeader*    pHeader;
      const DexStringId*  pStringIds;
      const DexTypeId*    pTypeIds;
      const DexFieldId*   pFieldIds;
      const DexMethodId*  pMethodIds;
      const DexProtoId*   pProtoIds;
      const DexClassDef*  pClassDefs;
      const DexLink*      pLinkData;
  
      /*
       * These are mapped out of the "auxillary" section, and may not be
       * included in the file.
       */
      const DexClassLookup* pClassLookup;
      const void*         pRegisterMapPool;       // RegisterMapClassPool
  
      /* points to start of DEX file data */
      const u1*           baseAddr;
  
      /* track memory overhead for auxillary structures */
      int                 overhead;
  
      /* additional app-specific data structures associated with the DEX */
      //void*               auxData;
};

struct DexOptHeader {
      u1  magic[8];           /* includes version number */
  
      u4  dexOffset;          /* file offset of DEX header */
      u4  dexLength;
      u4  depsOffset;         /* offset of optimized DEX dependency table */
      u4  depsLength;
      u4  optOffset;          /* file offset of optimized data tables */
      u4  optLength;
  
      u4  flags;              /* some info flags */
      u4  checksum;           /* adler32 checksum covering deps/opt */
  
      /* pad for 64-bit alignment if necessary */
  };
根据DexFile的数据结构可以得出 dexOffset 就是dex的偏移 ,dexLength 就是dex的大小, 这样就可以将dex整体dump出了
var base = ptr(dex_file).add(Process.pointerSize).readPointer();
var size = ptr(dex_file).add(Process.pointerSize + Process.pointerSize).readUInt();
posted @ 2023-03-05 16:53  明月照江江  阅读(528)  评论(0编辑  收藏  举报