背景
在进行对so的动态调试分析或者静态代码分析的过程中,都免不了和如下的区段相关信息打交道。
上图是ida工具中静态分析so文件代码中的展示,可以通过快捷键shift+F7进行展示(也可以用ndk自带的readelf程序进行查看区段信息)。
上图通过ndk自带的readelf程序进行查看so文件的区段信息(命令:readelf -S xx.so)。
下面就针对以上的区段名称信息做下梳理。
LOAD解析
它表示的是共享文件(so文件)的加载部分,linker会根据load区段中的偏移信息把整个so文件加载起来。
plt解析
plt也称为:过程链接表,主要用于函数和全局变量的调用。
Plt它是延迟绑定,延迟绑定的规则为只有在符号被真正引用时才进行重定位,而不是在刚开始就对所有的动态符号进行重定位,一方面加快了程序的启动,将整个动态加载时间分摊到程序运行期间,另一方面,对于共享库中没有用到的符号,不再进行重定位,节省了重定位的时间,随着共享库的发展更新,这种优势变得越来越明显。
plt 的好处在于所有需要重定位的指令跳转都保存在 plt 中,便于集中管理、索引,另一方面,plt 还实现了判断符号是否重定位并提供动态链接器的调用功能,这是延迟绑定技术的核心部分。
text解析
代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。
这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。
在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
bss解析
这个bss它包含着将出现在程序的内存映像中的未初始化数据,这个区段它不占用文件空间。
bss段的全称:Block Started by Symbol,它通常是指用来存放程序中未初始化的全局变量的一块内存区域,它是属于静态内存分配。当程序运行结束后有系统释放。
init_array解析
init_array是程序代码可以控制的最早时机, 其次才加载Jni_onload。这个也是很多在动态调试分析下断点的关键地方。
它包含着进程初始化所运行的函数指针数组。
它就如类对象的初始化构造函数。
fini_array解析
它存储的是终止函数段(也就是函数指针数组)。它是程序代码中最后执行的代码。
它就像类对象的析构函数。
got解析
它全名为 global offset table,即全局偏移表。
在执行的指令中,本来需要引用符号 A ,但是 A 存在于动态库中,链接过程并不知道它的地址,于是将 A 的地址部分改写为 GOT 表中某一项数据,在编译阶段 GOT 表中是没有真实数据的,但是在动态链接的加载阶段,动态链接器就可以将符号 A 的真实地址填写到 GOT 表中对应的数据项中,这样指令对 A 就产生了正确的引用。
GOT 中每一个表项占用 4 个字节(32位),表示运行时的符号的真实地址。它是针对外部符号引用的。
用来存放链接器找到的 函数/变量地址,也就是函数的绝对地址。
data解析
数据段:data segment.
它通常是指用来存放程序中已初始化的全局变量的一块内存区域,它是属于静态内存分配。
它在程序的内存映像中存在。
ret解析
它的作用:本程序装载进内存时,通过自己的rel表项告诉链接器,哪些地方需要重定位。
只要是rel开头的它都是表示跟重定位相关的信息。
rodata解析
它主要是字符串常量段。
它包含着只读数据,这些数据通常会参与进程映像的只读代码段。
extern解析
它表示是外部的导入函数,就是这个so文件中需要使用到的外部的函数。
data.rel.ro解析
它的作用就是表示程序初始化时的只读数据段。
ARM.extab解析
.ARM.extab 作为 .ARM.exidx 的附属存在,存放数据,但无法直接找到每段数据的入口。
ARM.exidx解析
它包含用于展开堆栈信息的部分。
dynsym和dynstr解析
dynsym和dynstr统称为符号表。
对于在链接阶段未解析的符号,就需要在动态链接阶段进行解析和重定位。
这些未解析的符号被保存在 .dynsym 中,而对应的字符串被保存在 .dynstr。
在 .dynstr 和 .dynsym 相关都是以 '\0' 结尾的动态符号表字符串信息。
dynsym是保存动态链接相关符号,记录其偏移值。
dynstr是dynsym的辅助段。
更详细可参考arm文档:https://developer.arm.com/
本文转载自微信公众号「编码安全」,可以通过以下二维码关注。转载本文请联系编码安全公众号。