OAT文件

发布于 2019-05-16  90 次阅读


OAT文件简介

OAT文件是在Android4.4中引入的。OAT是优化过的、用于ART虚拟机执行的DEX文件,类似于Dalvik的ODEX文件。

生成OAT文件

系统在安装APK时,会调用dex2oat自动生成OAT文件。用户也可以手动执行dex2oat命令,为指定的DEX文件生成OAT文件。
在执行dex2oat命令的时候,使用--dex-file参数指定传入的DEX路径(若有多个DEX文件,可以多次指定该参数),然后通过--oat-file参数指定OAT文件的输出路径(注意输出路径的写的权限)
例如

unzip app-release.apk classes.dex
mv classes.dex crackme.dex
adb push crackme.dex /data/local/tmp
adb shell dex2oat --dex-file=/data/local/tmp/crackme.dex --runtime-arg -Xms64m --runtime-arg -Xmx64m --oat-file=/data/local/tmp/crackme.oat
adb pull /data/local/tmp/crackme.oat .

OAT文件格式

OAT文件格式完全融入Android所特有的ELF格式。
识别OAT文件格式的一个有效方法是查看该ELF文件的符号表。
使用Android NDK包中的readelf工具查看oat的符号表

arm-linux-androideabi-readelf.exe -s demo.oat

一个OAT文件必须包含oatdata,oatexec,oatlastword三个符号

Symbol table '.dynsym' contains 4 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00001000 0xb4000 OBJECT  GLOBAL DEFAULT    4 oatdata
     2: 000b5000 0x75fe8 OBJECT  GLOBAL DEFAULT    5 oatexec
     3: 0012afe4     4 OBJECT  GLOBAL DEFAULT    5 oatlastword
  • oatdata符号指向的地址是OAT所在ELF的.rodata段,这里存放的是OAT文件头OATHeaderOAT的DEX文件头OATDexFile原始的DEX文件DexFileOAT的DEX类OatClass等信息。
  • oatexec符号指向的地址是OAT所在ELF的.text段,这里存放的是编译生成的Native指令代码。
  • oatlastword符号指向的地址是OAT文件结束处在ELF中的文件偏移,通过它可以确定OAT文件的内容在哪里结束

将OAT文件转换成DEX文件

由于OAT文件包含完整的DEX文件,取出OAT文件的方法非常简单;定位OAT文件中的DexFile结构体,将它的完整数据导出。
我们可以使用Android系统中的oatdump命令,使用该命令的--output参数可以将OAT中的所有DEX文件导出、放到指定的目录下。

oatdump --oat-file=demo.oat --output=demo.dex
  • 也可以使用010 Editor的脚本实现oat到dex的转化。
    将下面脚本保存为Oat2Dex.1sc,然后执行即可。
LittleEndian();

int i;
char filename[512];
filename = GetFileName();
int filenum = GetFileNum();
TFindResults r = FindAll("dex\n035");
//Printf("%d\n", r.count);
int pos, sz;
char dexname[512];
char ext[128];
for(i=0; i < r.count; i++) {
    pos = r.start[i];
    sz = ReadInt(pos + 0x20);
    Printf( "Found DEX at: 0x%lx, size: 0x%lx\n", pos, sz);

    // Copy data to clipboard and write to a new file
    SetSelection(pos, sz);
    CopyToClipboard();
    FileNew( "Hex" );
    PasteFromClipboard();
    SPrintf(ext, ".0x%lx.dex", pos);
    Memset(dexname, 0, 512);
    Strcat(dexname, filename);
    Strcat(dexname, ext);
    Printf("dexname: %s\n", dexname);

    // Save the new file to disk
    if(FileSave(dexname) < 0)
    {
        Printf("An error occured writing file '%s' of size 0x%lx.\n", dexname, sz);
        return -1;
    }
    FileClose();
    FileSelect(filenum);
    Printf("Write %s ok.\n", filename);

    // Make sure a big block of data is not still on the clipboard
    SetSelection(0, 1);
    CopyToClipboard();
    SetSelection(0, 0);
}


Printf("Done.\n");