2016年12月28日星期三

Android 逆向学习笔记 (七)- ELF 简单介绍

现在越来越多的安卓 app 为了保证软件的安全性,会使用 NDK 来进行 Native 开发,最后会产生一个 .so 这样的 ELF 文件,通过动态加载这个 ELF 文件调用隐藏在 .so 文件里的方法。

不过有的时候经过处理的 ELF 文件直接拖入 IDA 会报错,像下面这样,如果强行在 IDA 里查看的话会丧失很多有用信息,比较麻烦。



可以看 IDA 载入 ELF 的时候报了两个错, 1. SHT 入口位置不对,2. SHT 表大小或者偏移量不对。归纳来说就是 IDA 加载 ELF 的 SHT( Section Header Table) 内容出了错误。不过为什么出了这样的错误对安卓程序来说没有影响呢?

这是因为 Java 加载 .so 这样的 ELF 文件时不参照 Section Header Table 里的内容,所以开发者可以索性直接全部删除这个片段的内容,加大分析难度。这个时候如果需要分析的话最好可以先修复 ELF 文件结构。

ELF Structure

ELF 的主要有下面三个索引表片段。

1. ELF Header : 在 ELF 文件的最开始,保存了文件的路线图,描述该文件的组织情况。
2. Program Header Table : 告诉系统如何创建进程映像。用来构造进程映像的目标文件必须具有程序头部表,可重定位文件(e_type = 1)不需要这个表。
3. Section Header Table : 包含了描述文件节区的信息,每个节区在表中都有一项,每一项给出诸如节区名称、节区大小这类信息。用于链接的目标文件必须包含节区头部表,其他目标文件可以有,也可以没有这个表。

下面简单介绍一下各个索引表片段的内容,使用工具有 readelf(OS X - greadelf)和 xxd。
-h 选项代表显示 ELF Header 的内容,从这里可以看到 Size of this header: 52 (bytes),即 ELF Header 的长度为 52 = 0x34,使用 xxd 查看 ELF 前 52 bytes 的内容。
这里对照上图查看:
0x00000000: 457f 464c 01     01   0001      0000 0000 0000 0000
                      .ELF          |32    |LE|Version |Padding
0x00000010: 0003    0028             0001 0000 0000 0000 0034 0000
                      e_type |e_machine |e_version |e_entry   |e_phoff
0x00000020: 118c 0002 0000 0500 0034         0020               0007            0028
                      e_shoff     |e_flags      |e_ehsize |e_phentsize |e_phnum   |e_shentsize
0x00000030: 0016         0015
                      e_shnum  |e_shstrndx

具体含义不一一说明,可以看到整个 ELF 的结构在 ELF Header 就比较清楚了,这里跳过 Program Header Table 不表,因为我比较关注的是 Section Header Table

通过 ELF Headere_shoff 可以看到 SHT 的偏移量为 0x02118c,所以这里直接往 0x2118c 看。


可以看到 SHT 节头表起始为空节里没有数据,继续往下看第一个节。


0x000211b4 : 000b 0000     000b 0000 0002 0000 0114 0000
                        s_name_off  |s_type      |s_flags     |s_addr
0x000211c4 : 0114 0000 0740 0000  0002 0000 0001 0000
                       s_offset     | s_size       |s_link       |s_info
0x000311d4 : 0004 0000    0010 0000
                       s_addralign |s_entsize

对照下图查看 Section Header Table 的结构也比较清楚了,

ELF Fix

因为 SHT 在安卓引用 .so 文件时无关紧要,所以有两种保护情况:
1. 将 ELF Header 里和 SHT 有关的内容修改成错误的内容,但是不动 SHT。
2. 直接将 ELF 中的 SHT 删除。

第一种情况因为保留了正确的 SHT 所以只需要修复 ELF Header 就行,这时有下面几个需要注意的点:
1. e_shentsize = 0x28 = 40
2. e_shnum = (total_size - e_shoff) / e_shensize
3. e_shstrndx = e_shnum - 1

如果上述无法修复,那么就需要和 SHT 被删除的情况一样处理,可以使用附件中给出的一个小工具,此时修复原理比较复杂,可以在参考链接中查看具体内容。

* 附件 Github note-7。

参考链接: