ELF Header:
首先利用ndk系统里面的readelf命令,查看so文件的elf 头信息:
自己解析的话:
ELF Header数据结构
由上面两张表推导出,elf 头文件各个结构的位置:
例如一个elf文件头信息():
将这些字段,按照规定解析之后:
e_ident[]数组:
(也叫魔数Magic Number)给出了ELF的一些标识信息:
e_ident[]数组的下表以及取值:
e_ident[]是unsigned char,根据上面数据格式表,e_ident[]每一个位占一个byte大小。
e_ident[EL_MAG0]=e_ident[0]=”7f”;-----------7f 45 4c 46 固定格式,elf文件标志
e_ident[EL_MAG1]=e_ident[1]=”45”;------------由16进制转成ASCII码为E
e_ident[EL_MAG2]=e_ident[2]=”4c”; ------------由16进制转成ASCII码为L
e_ident[EL_MAG3]=e_ident[3]=”46”; ------------由16进制转成ASCII码为F
e_ident[EL_CLASS]=e_ident[4]=”01” -------------32位目标
e_ident[EL_DATA]=e_ident[5]=”01”; -------------之后数据的排序都是高位在前,就是在这边确定的。
e_ident[EL_VERSION]=e_ident[6]=”01”; --------没啥用
e_ident[PAD]=e_ident[7]=”00”; --------------------补0
e_ident[NIDENT]=e_ident[16]=””;-----------------这一位貌似没看到
e_type:
查看字段,可知03为DYN:
Readelf中也可看出来是DYN:
e_machine:
字段中没有,不过可通过readelf文件中推断,0x28即40为ARM
e_version:
表示当前版本:
e_entry:
e_phoff:
phoff---推断全称为program head off,即程序表头的偏移,可以查出程序表头的开始位置:
这个比较重要,这里面0x34即52=16*3+4,可以查出程序表头的开始位置如下图:
e_shoff:
为segment head off,即节区头部表格偏移,可以查出节区表头的开始地址:
也重要,0x3130,可以查出节区表头的开始地址如下图:
e_flags:
e_ehsize:
Elf head size,这个头文件的大小
可以看出这个头的大小为0x34即52字节
e_phentsize:
这个表示之后每一个处程序头的大小0x20即32字节
e_phnum:
表示程序头的个数,至此,根据程序头的偏移e_phoff=0x34(即52),程序头的大小e_phentsize=0x20(即32),以及这里的程序头的个数e_phnum=0x07(即7),就可以完全解析出每个程序头的精确位置。
e_shentsize:
表示节区头部表格的大小0x28=40,根据之前的e_shoff=0x3130可以精确定位第一个节区表头的位置
e_shnum:
表示节区头部表格,个数为0x15(即21)个。
至此,根据e_shoff 0x3130, e_shentsize 0x28以及这个e_shnum 0x15可以完全确定所有节区头部表格的精确位置。下图位置画错了。
e_shstrndx:
标记节区头部表格中,字符串节区头部表格的索引,即第几个节区是字符串节区头部表格。这个索引是从0开始。所以这边0x14即20就是第21个节区头部表格表示的是字符串的节区头部表格。如下图:
Program Headers:
使用NDK中的readelf –l xx.so查看program headers信息
Segment Headers:
使用NDK中的readelf –S xx.so查看segment headers信息
首先根据elf header中最后一个e_shstrndx=0x14确定节区头部中字符串节区头部的位置是第20个(索引位置,0开始),然后根据字符串节区头部位置中的sh_offset和sh_size确定字符串节区的位置。
字符串节区头部位置:
得出的字符串节区的位置
sh_name:
这个名称,根据上面查到的字符串节区来匹配名称:
根据字符串节区,得到0x01的名称为.shstrtab
查看readelf –S的到的结果相同
sh_type:
对比下面表格取值
sh_flags:
根据下面表格取值,可能不全。可以取多种值,相加即可
sh_add:
不知道有什么用,可能在实际运行的时候才有用
sh_offset:
静态偏移地址,根据这个可以查看到相对应节区的开始位置
sh_size:
相对应节区的大小,和sh_offset相结合,可以查看处对应节区的具体地址
sh_link:
sh_info:
sh_addralign:
sh_entsize