ELF檔案格式
0x00 準備
ELF全稱Executable and Linking Format,ELF檔案主要有3種,在檔案内部有2個byte用來指明該ELF檔案的類型(後文詳述)。為了分析ELF檔案的結構,準備好一個簡單的c語言“hello world”程式,編譯該檔案得到ELF檔案。
hw.c
#include <stdio.h>
int main(){
printf("hello world!\n");
return ;
}
指令:gcc -c hw.c
得到檔案hw.o
指令:gcc hw.c -o hw
得到檔案hw
在分析的過程中會:
- 使用hexdump指令檢視ELF檔案的二進制資料
- 使用readelf指令檢視ELF檔案的結構分析
- 使用objdump指令檢視ELF檔案的資訊
指令:hexdump -C hw
得到ELF檔案hw的二進制顯示:
f c |.ELF............|
e |..>.....@.@.....|
c8 |@...............|
e b |....@...@.....|
|........@.......|
|@.@.....@.@.....|
f8 f8 |................|
|................|
|......@.....|
c |@.............|
a0 c |................|
b0 |................|
c0 |..@.......@.....|
d0 c c |................|
|.. .............|
f0 e e |..........`.....|
........
0x01 ELF檔案頭(ELF Header):前64位元組
ELF檔案的前64個位元組(這裡指的是64位系統下,32位系統下稍有不同,是52個位元組)描述了ELF檔案的基本資訊,被稱為ELF頭
先分析前16個byte(0-15)
(0-3)byte:7f 45 4c 46
這個是ELF檔案的魔數,每一種檔案一般都有魔數,用來表明該檔案的類型,例如java的class檔案的魔數就是前4個byte :CAFEBABE
(4)byte : 02
這個位元組辨別此ELF檔案的平台類型,有3個可選值
0x00 :無效檔案
0x01 :32bit平台目标檔案(ELF檔案)
0x02 :64bit平台目标檔案
這裡是值為0x02表明是在64位系統下編譯的
(5)byte:01
這個位元組辨別二進制檔案的編碼類型,有3個可選值
0x00:無效編碼
0x01:小印第安排序(最大有意義的位元組占有最低的位址)
0x02:大印第安排序(最大有意義的位元組占有最高的位址)
這裡的值為0x01表明此ELF檔案使用的是小印第安排序
(6)byte:01
這個位元組指明ELF檔案格式的版本,目前必須為0x01
(7)byte :00 00 00 00 00 00 00 00 00
OS/ABI
(8)byte : 00
ABI version
(9-15)byte : 00 00 00 00 00 00 00
目前沒有意義,但是在将來可能有意義,規定必須每個byte都設定為0x00 ,但是其實不設定為0x00也可以,例如病毒程式就可以用這些byte來表明改ELF檔案是否已經被感染,或者是處于其他什麼狀态
再分析後48個byte(16-63)
(16-17)byte 02 00
這2個位元組表明文章開頭所說的ELF檔案的類型,(5)byte表明ELF檔案是小印第安排序,是以這2個位元組的值為0x0002 ,說明這是一個可執行檔案。這2個位元組的可選值如下:
0x0000 : 未知
0x0001 : 重定位檔案
0x0002 : 可執行檔案
0x0003 : 共享庫檔案
0x0004 : 核心檔案
0xff00 - 0xffff : 處理器相關
(18-19)byte 3e 00
這2個位元組表明機器架構,0x003e說明是x86_64機器
這個值的部分可選值有:
0x00 : No Manchine
0x02 : SPARC
0x03 : Intel 80386
0x12 : Sun SPARC 32+
0x2b : SPARC V9
0x3e : ADM 64
(20-23)byte 01 00 00 00
這4個位元組說明此目标檔案的版本,目前的版本均為1
(24-31)byte 40 04 40 00 00 00 00 00
這8個位元組是程式入口點位址,也就是main函數的邏輯位址,在64位系統下用8個位元組表示,32為系統下隻有4個位元組,這個值說明main函數的邏輯位址為:0x0000000000040440c8 19 00 00 00 00 00 00
(32-39)byte 40 00 00 00 00 00 00 00
這8個位元組是程式頭表(program header table)在目标檔案中的偏移位址,這裡的值為0x40,即64,說明程式頭表從第64位元組開始,也就是緊接着ELF Header之後。如果沒有程式頭表,這個值為0
(40-47)byte c8 19 00 00 00 00 00 00
這8個位元組是節頭表(section header table)在目标檔案中的偏移位址,這裡的值為0x19c8 ,說明節頭表在目标檔案的6600位元組。如果沒有節頭表這個值為0
(48-51)byte 00 00 00 00
這4個位元組就是一個與處理器相關的辨別(flag)
(52-53)byte 40 00
這2個位元組說明ELF Header本身的大小,64位系統的下是64位元組,是以是0x0040
(54-55)byte 38 00
這2個位元組辨別在程式頭表中每個程式頭的大小(以位元組為機關,每個程式頭的大小都是一樣的),此ELF檔案中每個程式頭的大小為0x38個位元組
(56-57)byte 09 00
這2個位元組說明程式頭表中程式頭的個數, 沒有的話就是0,此ELF檔案有9個程式頭
(58-59)byte 40 00
這2個位元組辨別在節頭表中每個節頭的大小(以位元組為機關,每個節頭的大小都是一樣的),此ELF檔案每個節頭的大小是0x40,即64個位元組
(60-61)byte 1e 00
這2個位元組辨別節頭表中節頭的個數,沒有的話就是0,0x1e說明ELF檔案有30個節頭
(62-63)byte 1b 00
這2個位元組表示的值是一個節頭表的索引值(是以這個值0x1b必然小于總數0x1e),通過這個索引值,可以在節頭表中找到一個特殊的節頭,在這個節頭中有每個節頭的字元串名字資訊。沒有這樣一個特殊的節頭的話這個值就是0