1.SO加固系列

dex加壳是保护APK的一种方式,然而只有dex加壳会影响APK的加载速度,另外通过内存dump也能轻易还原出原dex,在专业的加固方案中除了dex加壳还能经常见到对SO的保护,本系列文章将介绍基本的SO加固方案。本文是SO加固系列的第一篇,主要介绍SO加固时所需要用到的ELF中Section的相关知识。

2.ELF中的Section

ELF文件格式具体有三种类型:

  • 可重定位文件
  • 可执行文件
  • 共享目标文件(SO)

本文主要介绍ELF中的共享目标文件(.so文件)。在APK的保护中,经常将关键代码放在so库中,这样可以增大逆向的难度,但是有了IDA这种神器,也可大大降低逆向的难度,为了对抗IDA静态分析,就出现了so库的加壳。

存在于磁盘上的ELF文件和加载进内存的ELF文件并不完全一样:

elfsec2

Section Header Table位于ELF文件的末尾,在磁盘上(链接视图)的ELF文件中含有不同的节,比如:.text  .data  .got等,而Section Header Table则是存放各个Section的相关信息(大小,偏移等)。当ELF被加载进内存中时,会将多个Section合并成一个Segment(段),同一个段中具有相同的权限,通过/proc/pid/maps可以查看进程中各个Segment情况:

elfsec3

如上图所示,同一个so中可能有不同的Segment,同一个Segment一定具有相同的权限。

接下来让我们看看ELF Header中与Section相关的信息,ELF文件声明具体见(external/elfutils/libelf/elf.h)。32位ELF Header结构体定义如下:

其中与so加壳相关的主要有四个值:

elfsec0

其中e_shstrndx的含义为:Section Header Table中有一个Section专门用于存放各个Section的名字,为了能更快的找到Section的名字,于是在ELF头中保存了这个特殊Section的索引号。这个特殊的Section顺序保存了各个section的名字,并且以\0为分隔符,例子如下:

elfsec4

这个字符串表包含的各个字符串为:

elfsec5

Section Header Table中每一项大小相同(32位ELF中每一项占40字节),结构体定义如下:

在每一项中与加壳相关的主要有四个字段:

elfsec1

sh_name是指向string name section的偏移值,在加壳时可以先通过sh_name找到特定的section,然后这个section所在的偏移sh_offset和section大小sh_size读出整个section的内容,加密之后再写入即可。

3.ELF中的Segment

上一节在介绍section时已经提到了segment,在ELF文件中  一个segment = 多个section + 控制信息,并且每个segment都有一个Programe Header项,具体情况与section类似。具体格式见相关文档。

要注意一点的是:Android linker在加载时与链接视图无关而与执行视图有关,所以ELF Header中的e_shoff,e_shentsize,e_shnum,e_shstrndx可以被随意修改,修改完并不影响运行。但是与执行视图中segment的相关信息是不能被修改的。

4.使用Python解析ELF格式

为了能更好的熟悉ELF格式,最好的方法就是用代码说话,下面通过Python实现读取ELF各个section名,也是Python版加壳工具的雏形:

5.自定义section

在so中可以通过代码实现自定义section,比如添加一个名为hackme的section,并且在这个section中添加一个函数,另外添加一个名为hackme_data的section,并为其添加一个固定字符串(JNI下实现):

注意:data和method不能放在同一个段中,因为要保证权限相同。

6.init fini section

JNI下执行JNI_OnLoad之前会执行所有在init段注册的函数,在so执行结束前会执行所有在fini段中注册的函数,往init或fini中添加函数的方式如下:

7.参考文献

http://bbs.pediy.com/showthread.php?t=191649

ELF 文件格式分析

 

观看更多有关 的文章?

*

+
跳转到评论