Jimmy Chen

A Programmer

(原创)Odex文件二进制分析

Advertisements
Advertisements
Advertisements

  最近在看ART虚拟机相关的内容,稍微有了解的都能知道/data/dalvik-cache下的.dex后缀的文件和odex文件实际上都是修改过的ELF文件,网上有很多说明,但是貌似都没有找到一篇对一个odex或者说oat文件做分析的。所以博主这里就想着尝试对odex文件做一个简单分析。

odex文件总体信息

  这里博主拿SystemUI的oat文件(/data/dalvik-cache/arm64/system@product@priv-app@SystemUI@SystemUI.apk@classes.dex)做例子,下面是通过readelf -e system@product@priv-app@SystemUI@SystemUI.apk@classes.dex得出的ELF header、Section header、Program header以及Section到Segmemnt的映射关系如下所示

《(原创)Odex文件二进制分析》

《(原创)Odex文件二进制分析》

首先我们来看ELF header信息

这里我们先把通过readelf读出来的信息贴出来

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          3756960 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         12
  Section header string table index: 11

下面我们将代码中的ELF头定义贴出来

typedef struct elf64_hdr {
  unsigned char e_ident[EI_NIDENT];
  Elf64_Half e_type;
  Elf64_Half e_machine;
  Elf64_Word e_version;
  Elf64_Addr e_entry;
  Elf64_Off e_phoff;
  Elf64_Off e_shoff;
  Elf64_Word e_flags;
  Elf64_Half e_ehsize;
  Elf64_Half e_phentsize;
  Elf64_Half e_phnum;
  Elf64_Half e_shentsize;
  Elf64_Half e_shnum;
  Elf64_Half e_shstrndx;
} Elf64_Ehdr;

最后是通过010Editor使用十六进制显示的内容

《(原创)Odex文件二进制分析》

通过上面三个信息的对比,很多信息就很明显了有木有

  • 首先代码中的unsigned char e_ident[EI_NIDENT];的定义对应readelf信息的Magic,前面四个字节是固定的,定义如下:
#define ELFMAG0 0x7f
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'

随后紧接着的是文件的类型,这里是0x02,便是的是64位文件

// Object file classes.
enum {
  ELFCLASSNONE = 0,
  ELFCLASS32 = 1, // 32-bit object file
  ELFCLASS64 = 2  // 64-bit object file
};

随后是文件字节排布的类型,即是大端字节序还是小端字节序,这里是0x01,代表是小端字节序

// Object file byte orderings.
enum {
  ELFDATANONE = 0, // Invalid data encoding.
  ELFDATA2LSB = 1, // Little-endian object file
  ELFDATA2MSB = 2  // Big-endian object file
};

再接着代表文件的版本,固定位1,所以是0x01,到这里我们就将第一个分析e_ident[EI_NIDENT]的信息分析完了。

  • 接着我们分析struct余下的字段:

e_type代表的是OS ABI的类型,查看010Editor的信息,这里是0x03,对应的是GNU/Linux类型,也和readelf的信息对应上了

// OS ABI identification.
enum {
  ELFOSABI_NONE = 0,          // UNIX System V ABI
  ELFOSABI_HPUX = 1,          // HP-UX operating system
  ELFOSABI_NETBSD = 2,        // NetBSD
  ELFOSABI_LINUX = 3,         // GNU/Linux
  ELFOSABI_HURD = 4,          // GNU/Hurd
  ELFOSABI_SOLARIS = 6,       // Solaris
  ELFOSABI_AIX = 7,           // AIX
  ELFOSABI_IRIX = 8,          // IRIX
  ELFOSABI_FREEBSD = 9,       // FreeBSD
  ELFOSABI_TRU64 = 10,        // TRU64 UNIX
  ELFOSABI_MODESTO = 11,      // Novell Modesto
  ELFOSABI_OPENBSD = 12,      // OpenBSD
  ELFOSABI_OPENVMS = 13,      // OpenVMS
  ELFOSABI_NSK = 14,          // Hewlett-Packard Non-Stop Kernel
  ELFOSABI_AROS = 15,         // AROS
  ELFOSABI_FENIXOS = 16,      // FenixOS
  ELFOSABI_C6000_ELFABI = 64, // Bare-metal TMS320C6000
  ELFOSABI_C6000_LINUX = 65,  // Linux TMS320C6000
  ELFOSABI_ARM = 97,          // ARM
  ELFOSABI_STANDALONE = 255   // Standalone (embedded) application
};

后面的字段也类似,一次对应即可。这样ELF头信息就能很好的解读出来。接下来要说明的是section的信息了

Section hader解读

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .rodata           PROGBITS         0000000000001000  00001000
       00000000000bd000  0000000000000000   A       0     0     4096
  [ 2] .text             PROGBITS         00000000000be000  000be000
       00000000002aed00  0000000000000000  AX       0     0     4096
  [ 3] .data.bimg.rel.ro PROGBITS         000000000036d000  0036d000
       0000000000001560  0000000000000000   A       0     0     4096
  [ 4] .bss              NOBITS           000000000036f000  00000000
       0000000000005814  0000000000000000   A       0     0     4096
  [ 5] .dex              NOBITS           0000000000375000  00000000
       000000000000bed0  0000000000000000   A       0     0     4096
  [ 6] .dynstr           STRTAB           0000000000381000  0036f000
       00000000000000c7  0000000000000000   A       0     0     4096
  [ 7] .dynsym           DYNSYM           00000000003810c8  0036f0c8
       0000000000000120  0000000000000018   A       6     1     8
  [ 8] .hash             HASH             00000000003811e8  0036f1e8
       000000000000003c  0000000000000004   A       7     0     4
  [ 9] .dynamic          DYNAMIC          0000000000382000  00370000
       0000000000000070  0000000000000010   A       6     0     4096
  [10] .gnu_debugdata    PROGBITS         0000000000000000  00371000
       0000000000024338  0000000000000000           0     0     4096
  [11] .shstrtab         STRTAB           0000000000000000  00395338
       0000000000000063  0000000000000000           0     0     1

readelf section header获取到的信息如上,一共有11个section,其中第一个section是空的,这个是ELF的定义如此,那么我们要怎么在010Editor中找到对应字节的位置呢?首先在ELF header中,有一个关键的信息,就是section header的便宜,相信在上一节内容,你已经知道了,对应readelf的信息就是 Start of section headers: 3756960 (bytes into file),没错,这里就是和文件头的偏移量:3756960,即十六进制的3953A0。那么接下来我们在010Editor中跳转到3953A0位置看看

《(原创)Odex文件二进制分析》

这里蓝色标注的内容就是一个section header描述的信息,section header在代码中的描述如下所示

// Section header for ELF64 - same fields as ELF32, different types.
struct Elf64_Shdr {
  Elf64_Word  sh_name;
  Elf64_Word  sh_type;
  Elf64_Xword sh_flags;
  Elf64_Addr  sh_addr;
  Elf64_Off   sh_offset;
  Elf64_Xword sh_size;
  Elf64_Word  sh_link;
  Elf64_Word  sh_info;
  Elf64_Xword sh_addralign;
  Elf64_Xword sh_entsize;
};

第一个sh_name,这个需要特别说明一下,这个sh_name是一个Elf64_Word,实际是uint_32类型的,里面存储的是一个地址,指向
.shstrtab section中某个字串的开始地址。所以我们先看看.shstrtab section中存储的是什么内容吧,通过readelf中Section Header信息可以知道.shstrtab节的偏移地址位0x00395338,是的,这里直接读出来的地址就已经是16进制过的了。然后在010Editor中查看这个地址在存储的内容是什么呢?

《(原创)Odex文件二进制分析》

通过右边的字符串区可以看到一些可读信息,这里面存储的就是该odex文件中用到的section name。而在具体的section中,对应的sh_name的值就是.shstrtab section中的偏移量。

OK,因为博主也是最近才开始用010Editor查看并对照这代码来分析的,目前上面的信息暂时够用了,后续有要对各个section的内容做分析的时候,博主再补充了,或者各位看官有什么不懂得,可以提出来,后续博主再继续分析哈。

Advertisements
Advertisements
Advertisements

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

%d 博主赞过: