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