首页 > 其他分享 >【Android逆向】脱壳项目frida_dump 原理分析

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

时间:2023-03-05 17:14:00浏览次数:47  
标签:dex const name dump DefineClass file var frida Android

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

标签:dex,const,name,dump,DefineClass,file,var,frida,Android
From: https://www.cnblogs.com/gradyblog/p/17180934.html

相关文章

  • Android studio ListView的界面
    新建.java文件,定义一个实体类bt_list_adapter_type.java,作为ListView适配器的适配类型;publicclassbt_list_adapter_type{privateStringname;privateintim......
  • Android常用命令集锦
    1.android:对你只要输入android就会出来,SDKandAVDmanager我们可以更新SDK,增删修改AVD.2.androidlistavds:这条命令将会列出所有我们创建的android模拟器.3.andr......
  • Attempt to invoke virtual method ‘java.lang.String android.os.Bundle.getString(
    报错日志java.lang.NullPointerException:Attempttoinvokevirtualmethod'java.lang.Stringandroid.os.Bundle.getString(java.lang.String)'onanullobjectref......
  • Android学习-每日打卡APP-实现每日打卡
    继续写我的打卡APP-完成了每日打卡的功能,其实还是比较简单,因为和注册一样都是插入的过程同时还能实现自动计数的功能,把坚持天数自动计算出来,打卡后插入数据库效果,可以看......
  • Android-每日打卡APP-实现登录功能
    每日打卡APP新的进展-实现登录功能-昨天已经把注册功能实现了,今天也很快把登录功能做了出来,然后接着着手做其他功能,打卡功能写在下一篇博客能够实现登录和注册,注册相关的......
  • Androidstudio连接SQLite数据库报错not such table的相关解决
    错误展示明明就是按照创建第一个表的步骤来的,然后就是死活创建不出来第二张表,离谱啊家人们!错误解决针对于这个错误,只需要在SQLite类里面,将其中的version变量的值更改为......
  • Android Studio使用Anko库
    1.在项目build.gradle中指定插件及Anko库版本:plugins{id'com.android.application'version'7.4.2'applyfalseid'com.android.library'version'7.4.2'ap......
  • Android JNI 调用
    1.Android Studio创建native项目   对项目进行解释cmake_minimum_required(VERSION3.10.2)#Declaresandnamestheproject.project("jnitest")#Create......
  • 【Android】如何去掉默认标题栏
      1、在AndroidManifest.xml文件中修改并添加以下代码android:theme="@style/Theme.AppCompat.NoActionBar"2、在你想要去掉标题栏的页面Java文件添加相应代码(注......
  • Android进度表示
    在连接上数据库之后,一切都变得简单了呢!开心,很轻松地就能够将APP里面的相关内容写完啦!尝试了好久的连接Mysql数据库,最后还是没有成功;虽然Androidstudio里面自带的SQLite......