linux實踐之ELF文件分析

linux實踐之ELF文件分析html

下面開始elf文件的分析。linux

咱們首先編寫一個簡單的C代碼。數據結構

 

編譯連接生成可執行文件。ide

首先,查看scn15elf.o文件的詳細信息。ui

16進制形式查看scn15elf.o文件。編碼

 

查看scn15elf.o中各個段和符號表的信息。spa

各個段的詳細信息以下。.net

 

符號表的信息以下:3d

 

使用readelf命令查看各個段的詳細信息:unix

 

段表信息以下:

 

符號表信息以下:

 

下面讓咱們開始分析文件頭吧!

因爲個人虛擬機是32位的,我下面就主要以32位的系統進行分析,就不比較32位機和64位機的區別了。

32位系統elf頭文件的定義。

 

從上圖中,咱們可知,elf文件頭在32位系統中,佔52個字節。(16+2+2+4+4+4+4+4+2+2+2+2+2+2=52)轉換爲16進製表示爲0x34個字節。

 

因爲該虛擬機處理器使用小端法表示數據。

 

分析elf文件頭

第一行:

e_ident16個字節表示爲「7f45 4c46 0101 0100 0000 0000 0000 0000」,其中「7f45 4c46」表示「ELF」的ASCII碼錶。「0101」中前一個「01」表示是32位的機器,後一個「01」表示使用的是小端法。「0100」中的「01」表示的是版本號是01。剩下的0爲默認填充。

第二行:

e_type2個字節表示,爲「0001」,表示是一個重定向文件。

e_machine2個字節表示,爲「0003」,表示Inter 80386的處理器體系結構(32位)

e_version4個字節表示,爲「0000 0001」,表示的是當前版本。

e_entry4個字節表示,爲「0000 0000 」表示沒有入口點。

e_phoff4個字節表示,爲「0000 0000」表示沒有程序頭表。

第三行:

e_shoff4個字節表示,爲「0000 0228」表示段表的偏移地址。

e_flags4個字節表示,爲「0000 0000」表示未知處理器特定標誌。

e_ehsize2個字節表示,爲「0034」表示elf文件頭大小。

e_phentsize2個字節表示,爲「0000」,由於重定位文件沒有程序頭表。

e_phnum2個字節表示,爲「0000」,由於重定位文件沒有程序頭表。

e_shentsize2個字節表示,爲「0028」,表示段頭大小爲「0x28」字節,即爲40個字節(由此知道section header table裏面每個table的大小爲40個字節)。

第四行:

e_shnum2個字節表示,爲「000d」,表示段表入口有13個,這裏能夠知道,段有13

e_shstrndx2個字節表示,爲「000a」,表示段名串表在段表中的索引,(符號表的信息在段表的索引號是10)。

本身手工分析完後,能夠和「readelf」指令讀出的數據進行比較。

 

分析段表:

 

首先咱們根據剛剛在elf文件頭中讀到的段表偏移,找到段表的起始,咱們能夠看到偏移爲「0x228」。從上圖中段表的數據結構中能夠看出,段表佔40個字節(4*10=40字節即「0x28個字節」),這個結果和咱們從elf文件頭中讀到的結果一致。

 

因爲第一個段中有一部分數據沒有讀出來,因此咱們以第二個段(偏移爲0x0000268~0x00002a7)爲例分析:

sh_name4個字節表示,爲「0000 001f」,該值表明section header string table中的索引。

sh_type 4個字節表示,爲「0000 0001」,表示該段的類型是「SHT_PROGBITS」。

sh_flags 4個字節表示,爲「0000 0006」,指示該section在進程執行時的特性。其中最低位若是爲1 表示此節在進程執行過程當中可寫,次低位爲1表示此節的內容加載時要讀到內存中去,第三低位爲1表示這個節中的數據是可執行的機器指令。這裏代表該節在進程執行過程當中不可寫,在內容加載時要讀到內存中去,該節數據是可執行的機器指令。

sh_addr 4個字節表示,爲「0000 0000」,表示該節在進程中的起始地址爲「0x0000 0000」。

sh_offset4個字節表示,爲「0000 0034」表示該節在整個文件中的起始偏移量爲「0x34」。

sh_size4個字節表示,爲「0000 002e」,表示該節的字節大小爲2e

sh_link4個字節表示,爲「0000 0000」,表示沒有和該節相關聯的節。

sh_info4個字節表示,爲「0000 0000」表示沒有文件信息

sh_addralign4個字節表示,爲「0000 0001」,該值用於表示地址對齊信息,值爲1時表示不用地址對齊。

sh_entsize4個字節表示,爲「0000 0000」,對特定節(動態符號)纔有意義,這裏沒有意義。

總結:從section header table找到各個section頭的信息,仍是很簡單的。

只要知道其序列號(第幾個節)。尋找偏移「0x228+i個節*0x28」便可。

 

經過從section header table中讀到的信息,咱們來找一找這個字段的內容。

經分析知,該節內容起始,距文件頭0x34的位置,內容大小爲0x2e個字節。

 

如圖所示,該節的內容即爲圖中高亮的部分。咱們反彙編一下scn15elf.o文件,結果爲

 

對比發現兩個結果是一致的。

分析各個section。(.text .strtab .symtab .rodata

 

.text

分析見上一步的例子,已經分析完了。

.strtab

.strtab中存放的是符號的名字(符號表示一個固定的內存地址)。

計算該節的偏移=0x228+12*0x28=0x408

 

sh_name4個字節表示,爲「0000 0009」,該值表明section header string table中的索引。即.strtab節。

sh_type 4個字節表示,爲「0000 0003」,表示該段的類型是「SHT_STRTAB」。

sh_flags 4個字節表示,爲「0000 0000」,指示該section在進程執行時的特性。代表該節在進程執行過程當中不可寫,在內容加載時不須要讀到內存中去,該節數據不是可執行的機器指令。

sh_addr 4個字節表示,爲「0000 0000」,表示該節在進程中的起始地址爲「0x0000 0000」。

sh_offset4個字節表示,爲「0000 00198」表示該節在整個文件中的起始偏移量爲「0x198」。

sh_size4個字節表示,爲「0000 0016」,表示該節的字節大小爲16

sh_link4個字節表示,爲「0000 0000」,表示沒有和該節相關聯的節。

sh_info4個字節表示,爲「0000 0000」表示沒有文件信息

sh_addralign4個字節表示,爲「0000 0001」,該值用於表示地址對齊信息,值爲1時表示不用地址對齊。

sh_entsize4個字節表示,爲「0000 0000」,對特定節(動態符號)纔有意義,這裏沒有意義。

總結上面的分析是,該節距離文件頭偏移爲0x198,內容大小爲0x16

 

.symtab

該節中存放着全部section中定義的符號名字。描述了.strtab中的符號在「內存」中對應的「內存地址」。這裏的「內存地址」指的是偏移量,不是真的內存地址。

計算該節的偏移=0x228+11*0x28=0x3E0

 

sh_name4個字節表示,爲「0000 0001」,該值表明section header string table中的索引。即.symtab節。

sh_type 4個字節表示,爲「0000 0002」,表示該段的類型是「SHT_STRTAB」。

sh_flags 4個字節表示,爲「0000 0000」,指示該section在進程執行時的特性。代表該節在進程執行過程當中不可寫,在內容加載時不須要讀到內存中去,該節數據不是可執行的機器指令。

sh_addr 4個字節表示,爲「0000 0000」,表示該節在進程中的起始地址爲「0x0000 0000」。

sh_offset4個字節表示,爲「0000 00e8」表示該節在整個文件中的起始偏移量爲「0xe8」。

sh_size4個字節表示,爲「0000 00b0」,表示該節的字節大小爲16

sh_link4個字節表示,爲「0000 000c」,表示沒有和該節相關聯的節。

sh_info4個字節表示,爲「0000 0009」表示沒有文件信息

sh_addralign4個字節表示,爲「0000 0004」,該值用於表示地址對齊信息,值爲4時表示須要地址對齊。

sh_entsize4個字節表示,爲「0000 0010」,表示字節大小。

總結上面的分析是,該節距離文件頭偏移爲0xe8,內容大小爲0xb0

 

對比符號表裏的內容。

 

.rodata

rodata的意義一樣明顯,ro表明read only,即只讀數據(const)。關於rodata類型的數據,要注意如下幾點:
1常量不必定就放在rodata裏,有的當即數直接編碼在指令裏,存放在代碼段(.text)中。
對於字符串常量,編譯器會自動去掉重複的字符串,保證一個字符串在一個可執行文件(EXE/SO)中只存在一份拷貝。
2rodata是在多個進程間是共享的,這能夠提升空間利用率。
3有的嵌入式系統中,rodata放在ROM(norflash)裏,運行時直接讀取ROM內存,無須要加載到RAM內存中。
4在嵌入式linux系統中,經過一種叫做XIP(就地執行)的技術,也能夠直接讀取,而無須要加載到RAM內存中。

計算該節的偏移=0x228+5*0x28=0x2F0

 

sh_name4個字節表示,爲「0000 030」,該值表明section header string table中的索引。即.rodata節。

sh_type 4個字節表示,爲「0000 0001」,表示該段的類型是「SHT_STRTAB」。

sh_flags 4個字節表示,爲「0000 0002」,指示該section在進程執行時的特性。代表該節在進程執行過程當中不可寫,在內容加載時不須要讀到內存中去,該節數據不是可執行的機器指令。

sh_addr 4個字節表示,爲「0000 0000」,表示該節在進程中的起始地址爲「0x0000 0000」。

sh_offset4個字節表示,爲「0000 0062」表示該節在整個文件中的起始偏移量爲「0x62」。

sh_size4個字節表示,爲「0000 0013」,表示該節的字節大小爲13

sh_link4個字節表示,爲「0000 0000」,表示沒有和該節相關聯的節。

sh_info4個字節表示,爲「0000 0000」表示沒有文件信息

sh_addralign4個字節表示,爲「0000 0001」,該值用於表示地址對齊信息,值爲1時表示不用地址對齊。

sh_entsize4個字節表示,爲「0000 0000」,對特定節(動態符號)纔有意義,這裏沒有意義。

總結上面的分析是,該節距離文件頭偏移爲0x62,內容大小爲0x13

 

參考資料

一、 淺談Linux的可執行文件格式ELF

http://blog.chinaunix.net/uid-9068997-id-2010376.html

相關文章
相關標籤/搜索