Linux實踐四:ELF文件格式分析

1、分析ELF文件頭

2、經過文件頭找到section header table,理解內容

3、經過section header table 找到各section

4、理解常見.text .strtab .symtabl .rodata 等section

 段入口類型定義(/usr/include/elf.h)下面產生的hello是32位的數組

 

Hexdump –x hello函數

對應內容是7f45spa

 

 

前4字節,藍色部分,是一個魔數,表示這是一個ELF對象debug

 

下一個字節(右邊這個)01說明是個32位對象(64位的是02);3d

再下一個字節是01,說明使用的是小端方式(PC大多使用)版本控制

 

再下來一個字節01表示文件頭版本,剩下默認設置爲0調試

 

第二行:對象

 

.e_type(佔2字節)值爲0x0002,表示是可執行文件blog

(若爲0x0001,表示重定位文件)索引

e_machine(2字節)值爲0003,說明是intel 80386

e_version(4字節)值爲0x00000001,說明是當前版本(0,則是非法版本)

e_entry(4字節)值爲0x8048310

第三行

e_phoff(4字節)值爲0x00000034 ,表示程序頭表

e_shoff(4字節)值爲0x000017d4,表示段表的偏移地址

e_flags(4字節)0x00000000,表示未知處理器特色標誌(#define EF_SH_UNKNOWN 0x0)

e_ehsize(2字節)0x0034,表示ELF文件頭大小爲0x34H,(64位的是0x40H)

e_phentsize(2字節)0x0020,program header的大小是32比特。

e_phnum(2字節) 0x0009,program headers的數量是9個

e_ ehentsize(2字節) 0x0028,表示段頭大小爲40字節(由此可知section header table 裏面表個header的大小)

e_ shnum(2字節) 0x001f,表示段表入口地址有31個(由此知道段表有31個段)

e_shstrndx (2字節) 0x001c,表示段名串表的在段表中的索引號(由此知.shstrtab段(符號表)的信息在段表的索引號是28)

 

使用readelf -h hello查看ELF文件頭,將上述分析結果,與下面的結果能夠比較,查看本身分析得對不對。

 

 

 

e_type表示文件類型,2表示可執行文件。

e_machine:指明能夠在哪一種機器結構中運行。

e_version:指明版本信息 

e_entry:指明系統運行該程序時將控制權轉交到的虛擬地址的值,若是沒有則爲零。

e_phoff: program header table在文件中的字節(Byte)偏移offset,若是沒有program header table, 則該值爲零。

e_shoff: section header table在文件中的字節偏移,若是沒有section header table, 則該值爲零

e_flags: 有關處理器的信息

e_ehsize: elf header的大小,單位:字節

e_phentsize: 在program header table中一個entry的大小,前面提到過,program header table & section header table都是數組,因此它們的每個元素,即每個entry的大小,都是同樣的。

e_phnum: program header table中元素的個數,即entry的個數。

e_shentsize: section header table每個entry的大小,與e_phentsize相似。

e_shnum: section header table中元素的個數,即entry的個數。能夠看出來,這個program header table或者section header table的大小能夠用entry的個數乘以每個entry的大小獲得。

e_shstrndx: 指明string name table在section header table中的index。

  

section header table

 

 program header

 

 符號表:

 可使用readelf -s hello 查看

 由以前文件頭的分析可知:e_shoff(4字節)值爲0x000017d4,表示段表的偏移地址

 

e_ ehentsize(2字節) 0x0028,表示段頭大小爲40字節(由此可知section header table 裏面表個header的大小)

e_ shnum(2字節) 0x001f,表示段表入口地址有31個(由此知道段表有31個段)

段表大小 28H*1F=4D8H字節

 0x000017d4+0xH=0X00001CAC

因此從0x000017d4—0X00001CAC,存儲的是段表

在使用readelf -a hello時查看段表頭的狀況,

第一節區(17D4-17FC)

第二節區(17FC-1824)

第三節區(1824-184C)

 

第四節區(184C-1874)

 

 第五節區(1874-189C)

 

經過段表頭中存儲的每一個段的位偏移量以及段的大小找到段的具體內容。

.rela.textsection有關重定位的段,其偏移量不是有.text section的位偏移+段長度算的

.text section的位偏移+段長度計算出來的值是.data section的段偏移

反彙編指令和段的信息查看

 


 

Section Header table

目標文件的section header table能夠定位全部的section,它是一個Elf32_Shdr結構的數組,Section頭表的索引是這個數組的下標。有些索引號是保留的,目標文件不能使用這些特殊的索引。

Section包含目標文件除了ELF文件頭、程序頭表、section頭表的全部信息,並且目標文件section知足幾個條件:

目標文件中的每一個section都只有一個section頭項描述,能夠存在不指示任何section的section頭項。

每一個section在文件中佔據一塊連續的空間。 Section之間不可重疊。 目標文件能夠有非活動空間,各類headers和sections沒有覆蓋目標文件的每個字節,這些非活動空間是沒有定義的。

 

其中sh_name指出section的名字,它的值是後面將會講到的section header string table中的索引,指出一個以null結尾的字符串。sh_type是類別,sh_flags指示該section在進程執行時的特性。sh_addr指出若此section在進程的內存映像中出現,則給出開始的虛地址。sh_offset給出此section在文件中的偏移。其它字段的意義不太經常使用,在此不細述。

文件的section含有程序和控制信息,系統使用一些特定的section,並有其固定的類型和屬性(由sh_type和sh_info指出)。下面介紹幾個經常使用到的section:「.bss」段含有佔據程序內存映像的未初始化數據,當程序開始運行時系統對這段數據初始爲零,但這個section並不佔文件空間。「.data.」和「.data1」段包含佔據內存映像的初始化數據。「.rodata」和「.rodata1」段含程序映像中的只讀數據。「.shstrtab」段含有每一個section的名字,由section入口結構中的sh_name索引。「.strtab」段含有表示符號表(symbol table)名字的字符串。「.symtab」段含有文件的符號表,在後文專門介紹。「.text」段包含程序的可執行指令。


參考資料:

* .bss

  該sectiopn保存着未初始化的數據,這些數據存在於程序內存映象中。
  經過定義,當程序開始運行,系統初始化那些數據爲0。該section不佔
  文件空間,正如它的section類型SHT_NOBITS指示的同樣。
  
* .comment

   該section保存着版本控制信息。

* .data and .data1
  這些sections保存着初始化了的數據,那些數據存在於程序內存映象中。

* .debug

  該section保存着爲標號調試的信息。該內容是未指明的。

* .dynamic

  該section保存着動態鏈接的信息。該section的屬性將包括SHF_ALLOC位。
  是否須要SHF_WRITE是跟處理器有關。第二部分有更詳細的信息。

* .dynstr

  該section保存着動態鏈接時須要的字符串,通常狀況下,名字字符串關聯着
  符號表的入口。第二部分有更詳細的信息。

* .dynsym

  該section保存着動態符號表,如「Symbol Table」的描述。第二部分有更
  詳細的信息。
  
* .fini

  該section保存着可執行指令,它構成了進程的終止代碼。
  所以,當一個程序正常退出時,系統安排執行這個section的中的代碼。

* .got

  該section保存着全局的偏移量表。看第一部分的「Special Sections」和
  第二部分的「Global Offset Table」得到更多的信息。

* .hash

  該section保存着一個標號的哈希表。看第二部分的「Hash Table」得到更多
  的信息。

* .init

  該section保存着可執行指令,它構成了進程的初始化代碼。
  所以,當一個程序開始運行時,在main函數被調用以前(c語言稱爲main),
  系統安排執行這個section的中的代碼。

* .interp

  該section保存了程序的解釋程序(interpreter)的路徑。假如在這個section
  中有一個可裝載的段,那麼該section的屬性的SHF_ALLOC位將被設置;不然,
  該位不會被設置。看第二部分得到更多的信息。

* .line

  該section包含編輯字符的行數信息,它描述源程序與機器代碼之間的對於
  關係。該section內容不明確的。

* .note

  該section保存一些信息,使用「Note Section」(在第二部分)中提到的格式。

* .plt

  該section保存着過程鏈接表(Procedure Linkage Table)。看第一部分的
  ``Special Sections''和第二部分的「Procedure Linkage Table」。

* .rel<name> and .rela<name>

  這些section保存着重定位的信息,看下面的``Relocation''描述。
  假如文件包含了一個可裝載的段,而且這個段是重定位的,那麼該section的
  屬性將設置SHF_ALLOC位;不然該位被關閉。按照慣例,<name>由重定位適用
  的section來提供。所以,一個重定位的section適用的是.text,那麼該名字
  就爲.rel.text或者是.rela.text。

* .rodata and .rodata1

  這些section保存着只讀數據,在進程映象中構造不可寫的段。看第二部分的
  ``Program Header''得到更多的資料。

* .shstrtab

  該section保存着section名稱。

* .strtab

  該section保存着字符串,通常地,描述名字的字符串和一個標號的入口相關
  聯。假如文件有一個可裝載的段,而且該段包括了符號字符串表,那麼section
  的SHF_ALLOC屬性將被設置;不然不設置。

* .symtab

  該section保存着一個符號表,正如在這個section裏``Symbol Table''的
  描述。假如文件有一個可裝載的段,而且該段包含了符號表,那麼section
  的SHF_ALLOC屬性將被設置;不然不設置。

* .text

  該section保存着程序的``text''或者說是可執行指令。

相關文章
相關標籤/搜索