在Linux
系統(tǒng)使用過程中,我們經(jīng)常會看到elf32-i386
、ELF 64-bit LSB
等字樣。那么究竟ELF
是什么呢?
幾種常見的ELF文件
在Linux
下,我們經(jīng)gcc編譯
之后生成的可執(zhí)行文件屬于ELF
文件:
ELF
是一類文件類型,而不是特指某一后綴的文件。ELF
(Executable and Linkable Format,可執(zhí)行與可鏈接格式)文件格式,在Linux
下主要有如下三種文件:
- 可執(zhí)行文件(.out):
Executable File
,包含代碼和數(shù)據(jù),是可以直接運(yùn)行的程序。其代碼和數(shù)據(jù)都有固定的地址 (或相對于基地址的偏移 ),系統(tǒng)可根據(jù)這些地址信息把程序加載到內(nèi)存執(zhí)行。
- 可重定位文件(.o文件):
Relocatable File
,包含基礎(chǔ)代碼和數(shù)據(jù),但它的代碼及數(shù)據(jù)都沒有指定絕對地址,因此它適合于與其他目標(biāo)文件鏈接來創(chuàng)建可執(zhí)行文件或者共享目標(biāo)文件。
- 共享目標(biāo)文件(.so):
Shared Object File
,也稱動(dòng)態(tài)庫文件,包含了代碼和數(shù)據(jù),這些數(shù)據(jù)是在鏈接時(shí)被鏈接器(ld
)和運(yùn)行時(shí)動(dòng)態(tài)鏈接器(ld.so.l、libc.so.l、ld-linux.so.l
)使用的。
ELF格式
可結(jié)構(gòu)大致為:
ELF文件由4部分組成,分別是ELF頭(ELF header
)、程序頭表(Program header table
)、節(jié)(Section
)和節(jié)頭表(Section header table
)。
實(shí)際上,一個(gè)文件中不一定包含全部內(nèi)容,而且它們的位置也未必如同所示這樣安排,只有ELF頭
的位置是固定的,其余各部分的位置、大小等信息由ELF頭
中的各項(xiàng)值來決定。
readelf工具的使用
在Linux
下,我們可以使用readelf
命令工具可以查看ELF
格式文件的一些信息。下面我們先準(zhǔn)備一個(gè)動(dòng)態(tài)鏈接相關(guān)的demo:
文件1(main.c):
include "test.h"
int main(void)
{
print_hello();
return 0;
}
文件2(test.c):
include "test.h"
void print_hello(void) { printf("hello world\n"); }
文件3(test.h):
ifndef __TEST_H
#define __TEST_H
#include <stdio.h>
void print_hello(void);
#endif
執(zhí)行相關(guān)命令生成相關(guān)文件:.out文件
、.o文件
、.so文件
。如:
下面我們使用readelf
命令來查看這三類文件的一些信息。readelf
命令格式為:
readelf <option(s)> elf-file(s)
查看可執(zhí)行文件頭部信息:
查看可執(zhí)行文件頭部信息是,我們發(fā)現(xiàn)這樣一個(gè)問題,頭部信息中的類型竟然是共享庫文件,而我們查看的是可執(zhí)行文件,自相矛盾?
查了一些資料發(fā)現(xiàn):gcc編譯
默認(rèn)加了--enable-default-pie
選項(xiàng):
Position-Independent-Executable
是Binutils
,glibc
和gcc
的一個(gè)功能,能用來創(chuàng)建介于共享庫和通常可執(zhí)行代碼之間的代碼–能像共享庫一樣可重分配地址的程序,這種程序必須連接到Scrt1.o
。標(biāo)準(zhǔn)的可執(zhí)行程序需要固定的地址,并且只有被裝載到這個(gè)地址時(shí),程序才能正確執(zhí)行。PIE
能使程序像共享庫一樣在主存任何位置裝載,這需要將程序編譯成位置無關(guān),并鏈接為ELF
共享對象。
引入PIE
的原因是讓程序能裝載在隨機(jī)的地址,通常情況下,內(nèi)核都在固定的地址運(yùn)行,如果能改用位置無關(guān),那攻擊者就很難借助系統(tǒng)中的可執(zhí)行碼實(shí)施攻擊了。類似緩沖區(qū)溢出之類的攻擊將無法實(shí)施。而且這種安全提升的代價(jià)很小。
也就是說,pie
這是一種保護(hù)我們可執(zhí)行程序的一種手段。這里我們只是做實(shí)驗(yàn),我們可以加-no-pie
參數(shù)先把pie
給關(guān)掉:
可以看到,類型終于對得上了。ELF頭部
信息還包含有Entry point address
(入口地址)、Start of program headers
(程序頭的起始字節(jié))、Start of section headers
(節(jié)頭的起始字節(jié))等信息。
查看可重定位文件頭部信息:
查看共享目標(biāo)文件頭部信息:
同樣的,readelf
搭配其它參數(shù)可以查看ELF文件
的其它信息:
objdump工具的使用
objdump
工具用于顯示一個(gè)或多個(gè)目標(biāo)文件的信息。objdump
命令格式:
objdump <option(s)> <file(s)>
可執(zhí)行文件、可重定位文件與共享目標(biāo)文件都屬于目標(biāo)文件,所以都可以使用這個(gè)命令來查看一些信息。
查看可重定位文件反匯編信息:
查看可執(zhí)行文件反匯編信息:
查看共享目標(biāo)文件反匯編信息:
總結(jié)
以上就是本次的分享。簡單地介紹了ELF
文件的一些信息,同時(shí)介紹了分析ELF
文件的兩個(gè)工具。ELF
文件的內(nèi)容很多,并且比較抽象,詳細(xì)分析起來是個(gè)深坑。我們大致先進(jìn)行一個(gè)簡單的了解,我現(xiàn)在還沒有這個(gè)能力或者說還沒有這個(gè)需求去學(xué)習(xí)、分析這些底層的東西,之后如果深入學(xué)習(xí)時(shí)再做另外的分享。有興趣的同學(xué)可以跟我一起學(xué)
Linux教程:http://hgci.cn/linux/
Linux微課:http://hgci.cn/minicourse/play/linuxcourse
Linux就該這么學(xué):http://hgci.cn/linuxprobe/