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_ident用16個字節表示爲「7f45 4c46 0101 0100 0000 0000 0000 0000」,其中「7f45 4c46」表示「ELF」的ASCII碼錶。「0101」中前一個「01」表示是32位的機器,後一個「01」表示使用的是小端法。「0100」中的「01」表示的是版本號是01。剩下的0爲默認填充。
第二行:
e_type用2個字節表示,爲「0001」,表示是一個重定向文件。
e_machine用2個字節表示,爲「0003」,表示Inter 80386的處理器體系結構(32位)
e_version用4個字節表示,爲「0000 0001」,表示的是當前版本。
e_entry用4個字節表示,爲「0000 0000 」表示沒有入口點。
e_phoff用4個字節表示,爲「0000 0000」表示沒有程序頭表。
第三行:
e_shoff用4個字節表示,爲「0000 0228」表示段表的偏移地址。
e_flags用4個字節表示,爲「0000 0000」表示未知處理器特定標誌。
e_ehsize用2個字節表示,爲「0034」表示elf文件頭大小。
e_phentsize用2個字節表示,爲「0000」,由於重定位文件沒有程序頭表。
e_phnum用2個字節表示,爲「0000」,由於重定位文件沒有程序頭表。
e_shentsize用2個字節表示,爲「0028」,表示段頭大小爲「0x28」字節,即爲40個字節(由此知道section header table裏面每個table的大小爲40個字節)。
第四行:
e_shnum用2個字節表示,爲「000d」,表示段表入口有13個,這裏能夠知道,段有13個。
e_shstrndx用2個字節表示,爲「000a」,表示段名串表在段表中的索引,(符號表的信息在段表的索引號是10)。
本身手工分析完後,能夠和「readelf」指令讀出的數據進行比較。
分析段表:
首先咱們根據剛剛在elf文件頭中讀到的段表偏移,找到段表的起始,咱們能夠看到偏移爲「0x228」。從上圖中段表的數據結構中能夠看出,段表佔40個字節(4*10=40字節即「0x28個字節」),這個結果和咱們從elf文件頭中讀到的結果一致。
因爲第一個段中有一部分數據沒有讀出來,因此咱們以第二個段(偏移爲0x0000268~0x00002a7)爲例分析:
sh_name用4個字節表示,爲「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_offset用4個字節表示,爲「0000 0034」表示該節在整個文件中的起始偏移量爲「0x34」。
sh_size用4個字節表示,爲「0000 002e」,表示該節的字節大小爲2e。
sh_link用4個字節表示,爲「0000 0000」,表示沒有和該節相關聯的節。
sh_info用4個字節表示,爲「0000 0000」表示沒有文件信息
sh_addralign用4個字節表示,爲「0000 0001」,該值用於表示地址對齊信息,值爲1時表示不用地址對齊。
sh_entsize用4個字節表示,爲「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_name用4個字節表示,爲「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_offset用4個字節表示,爲「0000 00198」表示該節在整個文件中的起始偏移量爲「0x198」。
sh_size用4個字節表示,爲「0000 0016」,表示該節的字節大小爲16。
sh_link用4個字節表示,爲「0000 0000」,表示沒有和該節相關聯的節。
sh_info用4個字節表示,爲「0000 0000」表示沒有文件信息
sh_addralign用4個字節表示,爲「0000 0001」,該值用於表示地址對齊信息,值爲1時表示不用地址對齊。
sh_entsize用4個字節表示,爲「0000 0000」,對特定節(動態符號)纔有意義,這裏沒有意義。
總結上面的分析是,該節距離文件頭偏移爲0x198,內容大小爲0x16。
③.symtab節
該節中存放着全部section中定義的符號名字。描述了.strtab節中的符號在「內存」中對應的「內存地址」。這裏的「內存地址」指的是偏移量,不是真的內存地址。
計算該節的偏移=0x228+11*0x28=0x3E0。
sh_name用4個字節表示,爲「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_offset用4個字節表示,爲「0000 00e8」表示該節在整個文件中的起始偏移量爲「0xe8」。
sh_size用4個字節表示,爲「0000 00b0」,表示該節的字節大小爲16。
sh_link用4個字節表示,爲「0000 000c」,表示沒有和該節相關聯的節。
sh_info用4個字節表示,爲「0000 0009」表示沒有文件信息
sh_addralign用4個字節表示,爲「0000 0004」,該值用於表示地址對齊信息,值爲4時表示須要地址對齊。
sh_entsize用4個字節表示,爲「0000 0010」,表示字節大小。
總結上面的分析是,該節距離文件頭偏移爲0xe8,內容大小爲0xb0。
對比符號表裏的內容。
④.rodata節
rodata的意義一樣明顯,ro表明read only,即只讀數據(const)。關於rodata類型的數據,要注意如下幾點:
1、常量不必定就放在rodata裏,有的當即數直接編碼在指令裏,存放在代碼段(.text)中。
對於字符串常量,編譯器會自動去掉重複的字符串,保證一個字符串在一個可執行文件(EXE/SO)中只存在一份拷貝。
2、rodata是在多個進程間是共享的,這能夠提升空間利用率。
3、有的嵌入式系統中,rodata放在ROM(如norflash)裏,運行時直接讀取ROM內存,無須要加載到RAM內存中。
4、在嵌入式linux系統中,經過一種叫做XIP(就地執行)的技術,也能夠直接讀取,而無須要加載到RAM內存中。
計算該節的偏移=0x228+5*0x28=0x2F0。
sh_name用4個字節表示,爲「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_offset用4個字節表示,爲「0000 0062」表示該節在整個文件中的起始偏移量爲「0x62」。
sh_size用4個字節表示,爲「0000 0013」,表示該節的字節大小爲13。
sh_link用4個字節表示,爲「0000 0000」,表示沒有和該節相關聯的節。
sh_info用4個字節表示,爲「0000 0000」表示沒有文件信息
sh_addralign用4個字節表示,爲「0000 0001」,該值用於表示地址對齊信息,值爲1時表示不用地址對齊。
sh_entsize用4個字節表示,爲「0000 0000」,對特定節(動態符號)纔有意義,這裏沒有意義。
總結上面的分析是,該節距離文件頭偏移爲0x62,內容大小爲0x13。
參考資料