ELF檔案格式-第一講,詳解程式檔案頭
Elf檔案格式 ELF32or64
前言
本文參考連結: https://segmentfault.com/a/1190000007103522?utm_source=tuicool&utm_medium=referral
非原創。 在學習ELF的過程中記錄自己學習的歷程。
參考資料: LINUX二進位制分析
一丶ELF 程式頭
一個ELF檔案可以被標記為以下幾種型別
名詞 | 屬性 | 註解 |
---|---|---|
ET_NONE | 未知型別 | 這個標記表明了檔案型別不確定或者還未定義 |
ET_REL | 重定位檔案 | 如果elf檔案標記為了relocatable那麼意味著該檔案被標記為了一段可衝定位的程式碼,也稱為目標檔案。可重定位目標檔案通常是還未被連結到可執行程式的一段位置獨立程式碼的程式碼(position independent code)。在編譯完程式碼之後通常可以看到一個.o的格式的檔案,這種檔案包含了建立可執行檔案所需要的程式碼和資料。 |
ET_EXEC | 可執行檔案 | elf檔案如果為executable,那麼表明了這個檔案被標記為了可執行檔案。這種型別的檔案也成為程式,是一個程序開始執行的入口。 |
ET_DYN | 共享目標檔案 | ELF型別如果為dynamic意味著該檔案被標記為了一個動態的可連結的目標檔案,也稱為共享庫。這類共享庫會在程式執行的時候被裝載並且連結到程式的程序映象中。 |
ET_CORE | 核心檔案 | 在程序崩潰或者程序傳遞了一個SIGSEGV訊號(分段違規)時,會在核心檔案中記錄整個程序的映象資訊。可以使用GDB讀取這類檔案來輔助除錯並且查詢程式崩潰的原因。 |
在linux有一個readelf的小程式。 可以來檢視elf檔案。 可以看到原始的elf檔案頭。
其實所謂的格式就是 C語言中的結構體來做表,並且賦予每個欄位含義以及資訊。
例子:
>>> readelf -h main.out ELF 頭: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 類別: ELF32 資料: 2 補碼,小端序 (little endian) Version: 1 (current) OS/ABI: UNIX - System V ABI 版本: 0 型別: DYN (共享目標檔案) 系統架構: Intel 80386 版本: 0x1 入口點地址: 0x1070 程式頭起點: 52 (bytes into file) Start of section headers: 13980 (bytes into file) 標誌: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 12 Size of section headers: 40 (bytes) Number of section headers: 30 Section header string table index: 29
elf檔案的結構如下
#define EI_NIDENT 16
typedef struct
{
unsigned char e_ident[EI_NIDENT];
uint16_t e_type; ;表示檔案的型別,這裡為3 就是ET_DYN型別
uint16_t e_machine; ;表示平臺的版本,我使用gcc編譯所以標識 intel 8086
uint32_t e_version; ; 表示版本號
ElfN_Addr e_entry; ; 重要欄位標識了入口點位置程式的第一行程式碼位置
ElfN_Off e_phoff; ; 重要,標識了program table的在檔案的偏移開始位置
ElfN_Off e_shoff; ;section header table的偏移位置
uint32_t e_flags; ;儲存與檔案相關 特定於處理器的標識。
uint16_t e_ehsize;
uint16_t e_phentsize; ;重要欄位,表明了program table 每個結構體的大小
uint16_t e_phnum; ;重要欄位,表明programtable有多少項
uint16_t e_shentsize; ;表明了sectiontable每一項結構有多大
uint16_t e_shnum; ;表明了sectiontable有多少項
uint16_t e_shstrndx; ;節區頭部表格中與節區名稱字串相關的表項的索引。
} ElfN_Ehdr;
其實重要的就幾個欄位
1.ELF檔案標識頭(4個位元組即可)
- e_entry 記錄的程式開始位置
- e_phoff 記錄了program table在檔案的起始位置
- e_ phentsize 記錄了program table的每個結構大小
.5 e_phnum 表明了有多少個 program table
其餘的非必須的都可以設定為錯誤的值。對於程式來說是可以正常執行的。可以進行手動嘗試
1.2 詳解elf頭(32or64)
上面所說是實際應用過程中我們需要重點了解的內容
那麼下面就給出詳細的elf頭。讓我們更加的瞭解elf其他屬性以及作用。
1.2.1 簡介
可制定連結格式 最初是由UNIX系統實驗室開發並且釋出的。是作為應用程式二進位制介面的一部分。 工具介面委員會還在將發展的ELF標準選作為一種可移植的目標檔案格式。 可以在32位的intel體系結構上的很多作業系統中使用。
其中目錄檔案有三種類型,分別如下表所示:
名詞 | 檔案字尾 | 註解 |
---|---|---|
可重定位檔案(RelocatableFIle) | .o 結尾 | 包含適合於其他目標檔案連結來建立可執行檔案或者共享目標檔案的程式碼和資料。 |
可執行檔案(ExecutableFIle) | .exe | 包含適合於可執行的一個程式,此檔案規定了exec()如何建立一個程式的程序映像 |
共享目標檔案(Shared object FIle) | .so | 包含可在兩種上下文中連結的程式碼和資料。首先連結編輯器可以將它和其它可重定位檔案和共享目標檔案一起處理, 生成另外一個目標檔案。其次動態連結器(Dynamic Linker)可能將它與某 個可執行檔案以及其它共享目標一起組合,建立程序映像。 |
特點:
目標檔案全部是程式的二進位制表示。 目的就是直接在某種處理器上直接執行。
1.2.2 資料表示表格
目標檔案格式支援8位位元組/32位的體系架構。不過他們是可以擴充套件了。也就是可以執行在現在64位的機器上。
下圖則標識各個結構資訊的名稱 大小 對其方式等等。
名稱 | 大小 | 對齊 | 目的 |
---|---|---|---|
Elf32_Addr | 4 | 4 | 無符號程式地址 |
Elf32_Half | 2 | 2 | 無符號中等整數 也就是 unsigned short表示 |
Elf32_Off | 4 | 4 | 無符號檔案偏移 |
Elf32_SWord | 4 | 4 | 有符號整數 |
Elf32_Word | 4 | 4 | 無符號整數 |
unsigned char | 1 | 1 | 無符號1位元組 |
目標檔案中所有的資料結構都要遵守自然大小和對齊的規則。
如果有必要則會進行對齊操作。
1.2.3 Elf Hearder表示
32位結構如下:
/* ELF Header */
#define EI_NIDENT 16
typedef struct elfhdr {
unsigned char e_ident[EI_NIDENT]; /* ELF Identification */
Elf32_Half e_type; /* object file type */
Elf32_Half e_machine; /* machine */
Elf32_Word e_version; /* object file version */
Elf32_Addr e_entry; /* virtual entry point */
Elf32_Off e_phoff; /* program header table offset */
Elf32_Off e_shoff; /* section header table offset */
Elf32_Word e_flags; /* processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size */
Elf32_Half e_phentsize; /* program header entry size */
Elf32_Half e_phnum; /* number of program header entries */
Elf32_Half e_shentsize; /* section header entry size */
Elf32_Half e_shnum; /* number of section header entries */
Elf32_Half e_shstrndx; /* section header table's "section
header string table" entry offset */
} Elf32_Ehdr;
64位結構如下
typedef struct {
unsigned char e_ident[EI_NIDENT]; /* Id bytes */
Elf64_Quarter e_type; /* file type */
Elf64_Quarter e_machine; /* machine type */
Elf64_Half e_version; /* version number */
Elf64_Addr e_entry; /* entry point */
Elf64_Off e_phoff; /* Program hdr offset */
Elf64_Off e_shoff; /* Section hdr offset */
Elf64_Half e_flags; /* Processor flags */
Elf64_Quarter e_ehsize; /* sizeof ehdr */
Elf64_Quarter e_phentsize; /* Program header entry size */
Elf64_Quarter e_phnum; /* Number of program headers */
Elf64_Quarter e_shentsize; /* Section header entry size */
Elf64_Quarter e_shnum; /* Number of section headers */
Elf64_Quarter e_shstrndx; /* String table index */
} Elf64_Ehdr;
成員1: e_ident 是一些標識資訊。總共大小是16個位元組(32位的結構)
其中他是一個數組。 有一些ELF的標識資訊,用來標識陣列中不同下表的含義。
名稱 | 值 | 目的 |
---|---|---|
EI_MAG0 | 0 | 檔案標識 |
EI_MAG1 | 1 | 檔案標識 |
EI_MAG2 | 2 | 檔案標識 |
EI_MAG3 | 3 | 檔案標識 |
EI_CLASS | 4 | 檔案類 |
EI_DATA | 5 | 資料編碼 |
EI_VERSION | 6 | 檔案的版本 |
EI_PAD | 7 | 補齊位元組開始處 |
EI_NIDENT | 16 | e_ident[]的大小 |
這就是每個下標的意義。 那麼下面分別說下索引中每個值
其餘欄位意義如下
在LINUX下可以使用 readelf -h youelf 則可以看小elf檔案頭的資訊