游戏安全实验室 首页 技术入门 查看内容

 阅读目录

【Android】ELF格式及动态加载过程

发布于:2017-7-14 09:48   |    148114次阅读 作者: 管理员    |   原作者: TP   |   来自: 原创

目的

外网出现通过抹除ELF静态视图属性进行加固SO,本文对linker动态加载进行分析整理,方便更好的理解ELF文件格式及加载过程。

 

知识小纲

1、 ELF文件

2、 静态视图

a) 节区

b) STRTAB节

c) DYNSYM节

d) REL节

e) DYNAMIC节

3、 动态视图

a) 程序

b) 段说明

4、 linke动态加载

a) 装载

b) 链接

5、 小结

 

ELF文件

ELF文件是可执行链接格式(Executable and Linking Format)文件的简称,TIS(Tool Interface Standards)相应的标准说明。我们接触ELF文件有三类,可以简单理解为*.o之类的可重定位文件、*.so之类的共享目标文件,以及可执行文件。图1给出ELF文件的格式描述图(全篇绘图均以32位为例)

从图中,可以看出一个ELF文件,包含了ELF头、程序头表、节区、节头表部分。其中ELF头(包含两个表位置包含了ELF文件核心内容节区是必不可少的程序头和节头表根据使用场景可选。

静态视图使用场景IDA、readelf等工具查看ELF文件,这类场景通过SHT(Section Header Table)得到ELF文件布局,解析出各节内容展示用户。

动态视图的使用场景有如linker后续用linker统一代表所有解析器)加载ELF文件,这类场景通过PHT(Program Header Table)得到ELF文件布局,解析出动态加载需要的内容来使用。

通过上面的描述可知SHT和PHT中包含内容是有区分的PHT包含了动态加载的内容(该加载哪些东西内存)索引,SHT包含的是静态ELF文件内容展示。相对来,静态视图包含的内容为全量丰富内容,而动态视图包含linker加载需要的。

需要提及的是PHT中涉及到的Segment段概念,可以这么理解:段是动态视图索引的小单元(静态视图直接是使用节描述)其中N个节构成一个段,节可以不属于任何段。后续将有具体描述。

 

静态视图

一、 节区头

静态视图ELF头中获取到SHT在文件中的偏移e_shoff进而遍历SHT中的每个节区头来获取到展示信息从图1的ELF文件描述中可知SHT中为节信息如图3所示,每节区头中包含的节区信息有节区名、节区类型、节区位置等信息。

从节区头的结构信息可以了解到,ELF文件内容存放的一个较小单元存放着一类同样特性的文件信息,如STRTAB类型节中存放字符串信息、DYNAMIC类型中存放动态链接信息等。每个的解析方式,按照节类型不同,有不同的解析方式。

根据3中的节区头描述,可知道节区头的基本描述信息,这里需要提及到的是地址属性。如图4所示,节区头中包含了两个地址:sh_addrsh_offset。可以先这么理解,sh_offset文件偏移,既是常规文件读写方式的文件偏移地址。sh_addr则是虚拟地址,可以理解为加载进入内存后,相对于ELF模块基址的偏移地址(既是实际内存地址=虚拟地址+模块基址)。虚拟地址这个概念涉及到动态加载的内存对齐,在后面描述动态视图中讲解。

 

二、 STRTAB

该类型节是用来存放字符串信息,如图5所示,该节内容就是包含了一堆NULL结尾的字符序列用来提供给其它节的名字索引使用ELF文件中用一个word描述的名字属性,均是在相应STRTAB节(可能存在多个STRTAB类型节,具体用哪个节区头的link中属性确定)中的索引值。

如图4中可以看出一个ELF文件中可以包含多个STRTAB类型的节.dynstr(动态链接需要的符号.shstrtab(节区名称需要的符号).strtab(符号表符号

 

三、 DYNSYM

类型节存放着动态链接中需要的符号表信息,如图6所示,该节存放着系列的符号信息Elf32_Sym。每个符号信息包含了符号名字(link属性对应STRTAB节中的索引)值(虚拟地址或者绝对地址,取决于符号类型)属性。

如图6中选中的蓝色区域,对应的符号信息为图7中红框内容表示是个全局可见函数符号函数名为“lua_pushstring”虚拟地址为0x56c2c(如8所示,对应该函数代码地址)函数大小为0x84字节。

ELF文件动态加载过程的符号地址查询则是在DYNSYM类型节中查找,期间涉及到HASH节,该节可以直接理解为符号哈希表,用于快速查找到符号DYNSYM节中索引。

 

四、 REL

类型节中包含重定位信息,如图9所示每个重定位项Elf32_Rel)包含了重定位生效的地址及重定位项的类型符号信息info中保存着在对应DYNSYM节中的索引)。

涉及到的重定位类型ARM中一百多种,具体可参见ELF for the ARM® Architecture文件。这里提及常见的几种R_ARM_ABS32(如全局函数指针的方式调用外部函数R_ARM_GLOB_DAT(如局部函数指针方式调用外部函数R_ARM_JUMP_SLOT(如直接调用外部函数R_ARM_RELATIVE(基址重置具体可以通过自己编写DEMO程序,利用readelf查看。

如图10所示,查看.rel.plt节REL类型,得知lua_pushstring为R_ARM_JUMP_SLOT类型,其生效位置.got中,如图11所示

五、 DYNAMIC

类型节是个很重要但是很好理解的节,如图12所示,该节包含一系列动态链接中需要用到的信息索引。相应的类型如图13所示

利用readelf可以容易得到如图14所示。其中需要关注的其中涉及到的地址,均是虚拟地址。(动态使用的地址,均是虚拟地址。还有FINIT_ARRAY和INIT_ARRAY这两类可选属性在上述表格没有列出。

动态视图

一、 程序表

前面从静态视图角度介绍ELF文件,这里从动态视图过一遍。动态视图是根据linker等解析器动态加载的时候解析流程来ELF文件。ELF头中获取到PHT后,直接遍历每项内容进行ELF文件解析加载。如图15和16所示程序头包含了各个段的信息,如类型位置、大小、对齐信息等。

利用readelf工具快速得到图17所示展现,就是ELF程序头中常包含的内容有两个LOAD段、一个DYNAMIC段等同一个段有着相同的属性,如权限、对齐大小

 

二、 段说明

15中可以看出,只有LOAD段的节会加载进内存进行进一步使用,其它不相关段只有临时解析用途或者不用。另外动态视图中,段会包含多个,便于linker一次性映射进入内存。但是由于权限不同,所以一般需要划分两个LOAD。具体是可写和可执行对立。

 

linker动态加载

本文描述linker加载,是基于5.1.1_r14 AOSP代码分享7.x等新版本可能变动较大,会存在冲突但这不妨碍理解动态加载的核心原理。

这里提下前面静态视图中预埋的虚拟地址和文件偏移不一致问题,动态视图中可以看出由于权限问题每个段独立分开加载到内存。因此需要进行对齐操作所以中间可能出现间隙,进一步导致两个地址一致。

另外.bss节也会导致加载内存和文件占用不一致情况.bss节文件不占用大小)。故而除了将ELF文件映射到内存操作用到文件偏移,其余动态加载均是使用虚拟地址。

 

一、 装载

linker在确认需要加载到内存后(之前没加载过),通过ElfReaderELF文件进行反序列化。

验证ELF信息无误后,会根据LOAD段的长度(所有LOAD中最高和最低虚拟地址的差值,页对齐)预分配一段空间。然后按照LOAD中地址映射,如图18所示

其中文件大小不能超过内存大小内存大小大于文件大小的时候,将分配出来的多余空间清零,如.bss节

 

二、 链接

ELF装载到内存后,需要通过DYNAMIC段信息来实现链接。判断是否有依赖DT_NEEDSO),有的话进行递归加载。然后进行重定位操作。

重定位核心是把调用指令都跳转到合适的目标地址。如图19所示linker中对DT_JMPREL(.rel.plt)和DT_REL(.rel.dyn)进行了重定位操作。

通过前面REL节的介绍,基本可以推测到linker的重定位实现,如图20所示。既是遍历REL节里的重定位项,通过索引到DYNSYM节中获取符号信息。进而去获取该符号的位置(比如通过Elf32_Sym.st_name名字遍历其它SO符号信息得到地址),根据重定位类型填充进生效地址中。

接触到的重定位类型R_ARM_ABS32、R_ARM_GLOB_DAT、R_ARM_JUMP_SLOT均是通过符号地址+补齐大小|Thumb指令标志”公式计算。

重定位完,则是初始化函数的调用既是DT_INIT和DT_INIT_ARRAY处理。

 

小结

上面的讲解中可以基本了解ELF文件格式,及动态加载过程

面对抹除ELF文件静态视图的ELF加固,可以尝试利用这块知识进行修复(有修改偏移但信息还存在情况跟)。如果是完全抹除静态SHT那么修复难度相对较大。每个Android版本linker变动较大,解析内容的不确定性导致此类完全抹除安全方案无法在兼容性要求较高的产品上使用。


*转载请注明来自游戏安全实验室(Gslab.qq.com)

分享到:
踩0 赞0

收藏

上一篇:ida-调试中断

下一篇:[Android逆向分析]从Android源码看SO的加载

相关阅读
最新评论
B Color Image Link Quote Code Smilies

发表评论