一、簡介 可執行鏈接格式(Executable and Linking Format)最初是由 UNIX 系統實驗室(UNIX System Laboratories,USL)開發併發布的,作為應用程式二進位介面(Application Binary Interface,ABI)的一部分。工具介面標
一、簡介
可執行鏈接格式(Executable and Linking Format)最初是由 UNIX 系統實驗室(UNIX System Laboratories,USL)開發併發布的,作為應用程式二進位介面(Application Binary Interface,ABI)的一部分。工具介面標準(Tool Interface Standards,TIS)委員會將還在發展的 ELF 標準選作為一種可移植的目標文件格式,可以在 32 位 Intel 體繫結構上的很多操作系統中使用。
目標文件有三種類型:
-
可重定位文件(Relocatable File)包含適合於與其他目標文件鏈接來創建可執行文件或者共用目標文件的代碼和數據。
-
可執行文件(Executable File)包含適合於執行的一個程式,此文件規定了exec() 如何創建一個程式的進程映像。
-
共用目標文件(Shared Object File)包含可在兩種上下文中鏈接的代碼和數據。首先鏈接編輯器可以將它和其它可重定位文件和共用目標文件一起處理,生成另外一個目標文件。其次,動態鏈接器(Dynamic Linker)可能將它與某個可執行文件以及其它共用目標一起組合,創建進程映像。
-
目標文件全部是程式的二進位表示,目的是直接在某種處理器上直接執行。
二、目標文件格式
目標文件既要參與程式鏈接又要參與程式執行。出於方便性和效率考慮,目標文件格式提供了兩種並行視圖,分別反映了這些活動的不同需求。
文件開始處是一個ELF 頭部(ELF Header),用來描述整個文件的組織。節區部分包含鏈接視圖的大量信息:指令、數據、符號表、重定位信息等等。
程式頭部表(Program Header Table),如果存在的話,告訴系統如何創建進程映像。用來構造進程映像的目標文件必須具有程式頭部表,可重定位文件不需要這個表。
節區頭部表(Section Heade Table)包含了描述文件節區的信息,每個節區在表中都有一項,每一項給出諸如節區名稱、節區大小這類信息。用於鏈接的目標文件必須包含節區頭部表,其他目標文件可以有,也可以沒有這個表。
註意:儘管圖中顯示的各個組成部分是有順序的,實際上除了 ELF 頭部表以外,其他節區和段都沒有規定的順序
目標文件中的數據表示
目標文件中的所有數據結構都遵從“自然”大小和對齊規則。如果必要,數據結構可以包含顯式的補齊,例如為了確保4位元組對象按4位元組邊界對齊。數據對齊同樣適用於文件內部。
這裡使用android-ndk下麵的例子hello-jni.so來分析。
三、ELF Header部分
elf header數據如下:
ELF Header部分可以用下圖中的數據結構表示:
#define EI_NIDENT 16
typedef struct{
unsigned char e_ident[EI_NIDENT]; //目標文件標識信息
Elf32_Half e_type; //目標文件類型
Elf32_Half e_machine; //目標體繫結構類型
Elf32_Word e_version; //目標文件版本
Elf32_Addr e_entry; //程式入口的虛擬地址,若沒有,可為0
Elf32_Off e_phoff; //程式頭部表格(Program Header Table)的偏移量(按位元組計算),若沒有,可為0
Elf32_Off e_shoff; //節區頭部表格(Section Header Table)的偏移量(按位元組計算),若沒有,可為0
Elf32_Word e_flags; //保存與文件相關的,特定於處理器的標誌。標誌名稱採用 EF_machine_flag的格式。
Elf32_Half e_ehsize; //ELF 頭部的大小(以位元組計算)。
Elf32_Half e_phentsize; //程式頭部表格的表項大小(按位元組計算)。
Elf32_Half e_phnum; //程式頭部表格的表項數目。可以為 0。
Elf32_Half e_shentsize; //節區頭部表格的表項大小(按位元組計算)。
Elf32_Half e_shnum; //節區頭部表格的表項數目。可以為 0。
Elf32_Half e_shstrndx; //節區頭部表格中與節區名稱字元串表相關的表項的索引。如果文件沒有節區名稱字元串表,此參數可以為 SHN_UNDEF。
}Elf32_Ehdr;
其中,e_ident數組給出了ELF的一些標識信息,這個數組中不同下標的含義如表:
數據說明:
①e_ident[EI_MAG0]~e_ident[EI_MAG3]即e_ident[0]~e_ident[3]被稱為魔數(Magic Number),其值一般為0x7f,’E’,’L’,’F’。
②e_ident[EI_CLASS](即e_ident[4])識別目標文件運行在目標機器的類別,取值可為三種值:ELFCLASSNONE(0)非法類別;ELFCLASS32(1)32位目標;ELFCLASS64(2)64位目標。
③e_ident[EI_DATA](即e_ident[5])給出處理器特定數據的數據編碼方式。即大端還是小端方式。取值可為3種:ELFDATANONE(0)非法數據編碼;ELFDATA2LSB(1)高位在前;ELFDATA2MSB(2)低位在前。
④e_ident[EI_VERSION]](即e_ident[6])ELF頭部的版本號碼,此值必須是EV_CURRENT。
⑤e_ident[EI_PAD](即e_ident[7])標記e_ident中未使用位元組的開始,初始化為0。
其它各個欄位的含義如下:
四、Program Header Table部分
數據結構如下所示:
/* Program segment header. */ typedef struct { Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Word p_filesz; /* Segment size in file */ Elf32_Word p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Word p_align; /* Segment alignment */ } Elf32_Phdr;
其中p_type的定義如下:
/* Legal values for p_type (segment type). */ #define PT_NULL 0 /* Program header table entry unused */ #define PT_LOAD 1 /* Loadable program segment */ #define PT_DYNAMIC 2 /* Dynamic linking information */ #define PT_INTERP 3 /* Program interpreter */ #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved */ #define PT_PHDR 6 /* Entry for header table itself */ #define PT_TLS 7 /* Thread-local storage segment */ #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ #define PT_HISUNW 0x6fffffff #define PT_HIOS 0x6fffffff /* End of OS-specific */ #define PT_LOPROC 0x70000000 /* Start of processor-specific */ #define PT_HIPROC 0x7fffffff /* End of processor-specific */
p_flag表示該該段是否可讀可寫可執行
/* Legal values for p_flags (segment flags). */ #define PF_X (1 << 0) /* Segment is executable */ #define PF_W (1 << 1) /* Segment is writable */ #define PF_R (1 << 2) /* Segment is readable */ #define PF_MASKOS 0x0ff00000 /* OS-specific */ #define PF_MASKPROC 0xf0000000 /* Processor-specific */
五、Section Header Table部分
ELF 頭部中,e_shoff 成員給出從文件頭到節區頭部表格的偏移位元組數;e_shnum給出表格中條目數目;e_shentsize 給出每個項目的位元組數。從這些信息中可以確切地定位節區的具體位置、長度。
數據結構如下:
typedef struct{
Elf32_Word sh_name; //節區名,是節區頭部字元串表節區(Section Header String Table Section)的索引。名字是一個 NULL 結尾的字元串。
Elf32_Word sh_type; //為節區類型
Elf32_Word sh_flags; //節區標誌
Elf32_Addr sh_addr; //如果節區將出現在進程的記憶體映像中,此成員給出節區的第一個位元組應處的位置。否則,此欄位為 0。
Elf32_Off sh_offset; //此成員的取值給出節區的第一個位元組與文件頭之間的偏移。
Elf32_Word sh_size; //此 成 員 給 出 節 區 的 長 度 ( 字 節 數 )。
Elf32_Word sh_link; //此成員給出節區頭部表索引鏈接。其具體的解釋依賴於節區類型。
Elf32_Word sh_info; //此成員給出附加信息,其解釋依賴於節區類型。
Elf32_Word sh_addralign; //某些節區帶有地址對齊約束.
Elf32_Word sh_entsize; //某些節區中包含固定大小的項目,如符號表。對於這類節區,此成員給出每個表項的長度位元組數。
}Elf32_Shdr;
sh_type欄位:
sh_flags欄位:
sh_flags欄位定義了一個節區中包含的內容是否可以修改、是否可以執行等信息。如果一個標誌位被設置,則該位取值為1。未定義的各位都設置為0。
SHF_WRITE 0×1
SHF_ALLOC 0×2
SHF_EXECINSTR 0×4
SHF_MASKPROC 0xF0000000
其中已經定義了的各位含義如下:
SHF_WRITE: 節區包含進程執行過程中將可寫的數據。
SHF_ALLOC: 此節區在進程執行過程中占用記憶體。某些控制節區並不出現於目標文件的記憶體映像中,對於那些節區,此位應設置為 0。
SHF_EXECINSTR: 節區包含可執行的機器指令。
SHF_MASKPROC: 所有包含於此掩碼中的四位都用於處理器專用的語義。
sh_link和sh_info欄位:
根據節區類型的不同,sh_link 和 sh_info 的具體含義也有所不同:
六、特殊節區
①以“.”開頭的節區名稱是系統保留的。應用程式可以使用沒有首碼的節區名稱,以避免與系統節區衝突。
②目標文件格式允許人們定義不在上述列表中的節區。
③目標文件中也可以包含多個名字相同的節區。
④保留給處理器體繫結構的節區名稱一般構成為:處理器體繫結構名稱簡寫 + 節區名稱。
⑤處理器名稱應該與 e_machine 中使用的名稱相同。例如 .FOO.psect 街區是由FOO 體繫結構定義的 psect 節區。
七、字元串表(String Table)
首先要知道,字元串表它本身就是一個節區,從第二章描述中可知,每一個節區都存在一個節區頭部表項與之對應,所以字元串表這個節區也存在一個節區頭部表項對應,而在elf文件頭部結構中存在一個成員e_shstrndx給出這個節區頭部表項的索引位置。因此可以通過
shstrab = (rt_uint8_t *)module_ptr +shdr[elf_module->e_shstrndx].sh_offset;
字元串表節區包含以NULL(ASCII碼0)結尾的字元序列,通常稱為字元串。ELF目標文件通常使用字元串來表示符號和節區名稱。對字元串的引用通常以字元串在字元串表中的下標給出。
一般,第一個位元組(索引為 0)定義為一個空字元串。類似的,字元串表的最後一個位元組也定義為 NULL,以確保所有的字元串都以NULL結尾。索引為0的字元串在不同的上下文中可以表示無名或者名字為 NULL的字元串。
允許存在空的字元串表節區,其節區頭部的sh_size成員應該為0。對空的字元串表而言,非0的索引值是非法的。
在使用、分析字元串表時,要註意以下幾點:
①字元串表索引可以引用節區中任意位元組
②字元串可以出現多次
③可以存在對子字元串的引用
④同一個字元串可以被引用多次
⑤字元串表中也可以存在未引用的字元串
先介紹這麼多,其它的信息大家自己參考:
非蟲大大附圖:http://bbs.pediy.com/attachment.php?attachmentid=74501&d=1355835585
ELF文件格式分析:http://staff.ustc.edu.cn/~sycheng/sst/exp_crack/ELF.pdf
ELF文件格式官方文檔:http://download.csdn.net/detail/walkingman321/3016369
作者:AloneMonkey 來源: Coder
問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com 下載問啊APP,參與官方懸賞,賺百元現金。
QQ群290551701 聚集很多互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!