0%

获取dex之dump内存

对于加固,是将加密后的dex文件与壳文件合并生成新的class.dex文件,然后签名重打包生成加固后的apk文件。而对于壳程序加载原dex文件,是dalvik虚拟机加载加固后的apk里的classes.dex文件,并使用attachBaseContext方法以及onCreate方法进行解密原dex文件并启动原程序。但是无论进行了怎样的加密,最后都是需要经历解密动态加载到内存中的,利用这一点即可进行dump出dex文件。

dump内存法一

通过分析底层加载dex源码发现libdvm.so中的dvmDexFileOpenPartial函数,该函数有两个参数,一个是dex的起始地址,一个是dex的大小。于是可以使用ida进行动态调试获取信息。

  • 安装好apk,并以调试方式运行

  • 启动调试服务并进行端口转发

  • pull出/system/lib/libdvm.so文件

  • libdvm.so加载入ida并在dvmDexFileOpenPartial函数开始处下断点

  • attach进程
    点击Debugger->Attach to process,在选择框中选择apk对应的包名(即apk运行的进程名)并记录下ID,然后点击OK

  • 在PC的xxx(此处为ID)端口与手机的相应端口之间建立连接
    adb forward tcp:8700 jdwp:xxx(此处为ID)

  • 使用jdbjava层将apk attach到电脑上
    jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700

  • F9运行ida,一路ok程序停在预先下好的断点处
    此时寄存器R0中对应的就是dex文件的起始地址,R1对应的就是dex文件的大小

  • 使用IDC进行dump内存获取dex,脚本如下:

    1
    2
    3
    4
    5
    6
    7
    8
    static main(void)
    {
    auto fp, dex_addr, end_addr;
    fp = fopen("E:\\Android\\temp\\dump.dex", "wb");
    end_addr = r0 + r1;
    for(dex_addr = r0; dex_addr < end_addr; dex_addr++)
    fputc(Byte(dex_addr), fp);
    }
  • 因为Dalvik虚拟机下对运行的dex文件做了优化,真正在内存中运行的是odex文件

    • 使用baksmali对odex文件进行反编译
    • 使用smali进行编译成dex文件
  • 得到了dex文件即可对其进行分析了

dump内存法二

  • 按动态调试流程进行

  • 在获取到进程ID后打开adb shell
    输入cat /proc/xxx(进程ID)/maps,在结果里找到对应程序的dex文件地址

  • 在ida中使用IDC进行dump内存获取dex,脚本如下:

    1
    2
    3
    4
    5
    6
    7
    8
    static main(void){
    auto fp, beg_addr, end_addr, dex_addr;
    fp = fopen("E:\\Android\\atemp\\dump.dex", "wb");
    beg_addr = 0xaaaaaaaa;
    end_addr = 0xbbbbbbbb;
    for (dex_addr = beg_addr; dex_addr < end_addr; dex_addr++ )
    fputc(Byte(dex_addr), fp);
    }
  • 但此法有问题,目前还没弄明白,有待研究,如下图:

    圈中的是我用法一得到的,可以dump出来,但在此时进入法二的进程maps(图中横线)中却得不到真正的dex地址

dump内存法三

使用ZjDroid。ZjDroid是基于Xposed Framewrok的动态逆向分析模块,逆向分析者可以通过ZjDroid完成以下工作:

  • DEX文件的内存dump

  • 基于Dalvik关键指针的内存BackSmali,有效破解加固应用

  • 敏感API的动态监控

  • 指定内存区域数据dump

  • 获取应用加载DEX信息。

  • 获取指定DEX文件加载类信息。

  • dump Dalvik java堆信息。

  • 在目标进程动态运行lua脚本。

art虚拟机

上述都是Dalvik虚拟机下的。对于art虚拟机下,dump的点在于libart.so的OpenMemory函数。而且dump出来的文件是OAT文件,OAT文件类似于Dalvik的ODEX文件。由于OAT文件中包含完整的DEX文件,取出OAT文件的方法非常简单:定位OAT文件中的DexFile结构体然后将数据完整导出即可。