
Linux及安全實踐四——ELF文件格式分析
一、ELF文件格式概述
1. ELF:是一種對象文件的格式,用於定義不同類型的對象文件中都放了什么東西、以及都以什么樣的格式去放這些東西。
二、分析一個ELF文件
以一個最簡單的helloworld程序為例
1. ELF文件頭
使用工具查看ELF文件頭:readelf -h obj
在/usr/include/elf.h中可以找到文件頭結構定義:
大小總共為64字節,換算成十六進制為0x40。在十六進制代碼中找到前0x40字節,即為文件頭信息部分(閱讀時注意反序問題):
(1)identification
第一部分:占四個字節。7f 45 4c 46,對應ASCII碼.ELF,表示這是一個ELF對象。
第二部分:占一個字節。02表示是一個64位對象。
第三部分:占一個字節。01表示是小端表示法。
第四部分:占一個字節。01表示文件頭版本。
其余默認為0。
(2)information
e_type:兩個字節,01 00表示是一個重定位文件。
e_machine:兩個字節,3e 00表示是intel80386處理器體系結構。
e_version:四個字節,01 00 00 00表示是當前版本。
e_entry:八個字節,00 00 00 00 00 00 00 00表示當前程序沒有入口點。
e_phoff:八個字節,00 00 00 00 00 00 00 00表示沒有程序頭表。
e_shoff:八個字節,90 02 00 00 00 00 00 00表示段表的偏移地址在00 00 00 00 00 00 02 90處。
e_flags:四個字節,00 00 00 00表示未知處理器特定標志#define EF_SH_UNKNOWN 0x0。
e_ehsize:兩個字節,40 00表示elf文件頭大小為00 40(64個字節)。
e_phentsize:兩個字節,00 00表示重定位文件沒有程序頭表。
e_phnum:兩個字節,00 00表示重定位文件沒有程序頭表。
e_ehentsize:兩個字節,40 00 表示段頭大小為00 40(64字節),section header table中每個header的大小。
e_shnum:兩個字節,0d 00表示段表入口有13個,即段表有13段。
e_shstrndx:兩個字節,0a 00 表示段表字符串在段表中的索引號,.shstrab段的段表索引號為00 0a,即10。
2. 通過文件頭找到各個節
使用工具查看段表信息:readelf -S obj
(1)找到段表
在文件頭中e_shoff可以找到段表偏移地址00 00 00 00 00 00 02 90,從這個地址去查找段表。
段表長度由e_ehentsize為00 40(64字節)。
段表個數由e_shnum可知有13個。
/usr/include/elf.h中可以找到段表結構:
(2)分析一個段表
第一個段:全為零,不表示任何段。
第二個段:
sh_name:四個字節,20 00 00 00表示該段名稱在.shstrtab中偏移量,為.test節。
sh_type:四個字節,01 00 00 00表示這個段擁有程序所定義的信息,其格式和含義完全由該程序確定,這里表示PROGBITS。
sh_flags:八個字節,06 00 00 00 00 00 00 00表示alloc和execute。
sh_addr:八個字節,00 00 00 00 00 00 00 00表示是section在內存中的虛擬地址,.o文件不需要執行,這里都是0。
sh_offset:八個字節,40 00 00 00 00 00 00 00表示是section與文件頭之間的偏移。
sh_size:八個字節,11 00 00 00 00 00 00 00表示文件里面section占用的大小。
sh_link:四個字節,00 00 00 00表示沒有鏈接信息。
sh_info:四個字節,00 00 00 00表示沒有輔助信息。
sh_addralign:八個字節,01 00 00 00 00 00 00 00表示字節對齊長度。
sh_entsize:八個字節,00 00 00 00 00 00 00 00表示沒有入口。(3)所有段表
第三個段:
段名:.rel.text
類型:RELA
標志:info
相對文件頭偏移:0x1e0
占用大小:0x30
第四個段:
段名:.data
類型:PROGBITS
標志:write、alloc
相對文件頭偏移:0x51
占用大小:0
第五個段:
段名:.bss
類型:NOBITS
標志:write、alloc
相對文件頭偏移:0x51
占用大小:0
第六個段:
段名:.rodata
類型:PROGBITS
標志:alloc
相對文件頭偏移:0x51
占用大小:0x0b
第七個段:
段名:.comment
類型:PROGBITS
標志:merge、strings
相對文件頭偏移:0x5c
占用大小:0x26
第八個段:
段名:.note.GNU-stack
類型:PROGBITS
標志:無
相對文件頭偏移:0x82
占用大小:0
第九個段:
段名:.eh_frame
類型:PROGBITS
標志:alloc
相對文件頭偏移:0x88
占用大小:0x38
第十個段:
段名:.rela.eh_frame
類型:RELA
標志:info
相對文件頭偏移:0x210
占用大小:0x18
第十一段:
段名:.shstrtab
類型:STRTAB
標志:無
相對文件頭偏移:0x228
占用大小:0x61
第十二段:
段名:.symtab
類型:STRTAB
標志:無
相對文件頭偏移:0xc0
占用大小:0x0108
第十三段:
段名:.strtab
類型:STRTAB
標志:無
相對文件頭偏移:0x1c8
占用大小:0x11
三、理解常見節
1. .text節:本節中是可執行指令的集合
通過剛才的信息,我們可以從文件中偏移0x40處找到大小為0x11的 .text節:
可以通過反匯編該程序來查看:
2. .rodata:本節是只讀數據,ro代表read only
從偏移0x51處找到大小為0x0b的 .rodata節:
使用ASCII碼對照表翻譯數據為hello 5309,即.c文件中的字符串:
2. .comment:本節用來存放編譯器版本信息
從偏移0x5c處找到大小為0x26的 .comment節:
3. .symtab:本節存放所有section中定義的符號名字,一般是變量、函數shstrtab及symtab經常引用strtab中的字符串
從偏移0xc0處找到大小為0x0108的 .symtab節:
4. .strtab:本節是段表的字符串表
從偏移0x1c8處找到大小為0x11的 .strtab節:
數據用“0”分隔出了三部分,用ASCII碼翻譯:
65 6c 66 2e 63:elf.c
6d 61 69 6e:main
70 75 74 73:puts