理論——ELF可執(zhí)行文件格式分析

在分析Binonic的Linker之前辑奈,我們先介紹Android的可執(zhí)行文件格式进萄,linker本事并不是很復(fù)雜,但是磁玉,如果對(duì)可執(zhí)行文件格式不了解停忿,就不太容易理解程序的邏輯。了解可執(zhí)行文件的另一個(gè)好處是能開(kāi)發(fā)出一些特殊功能的軟件蚊伞。Hook系統(tǒng)API軟件

Android的可執(zhí)行文件和動(dòng)態(tài)庫(kù)就是Linux的ELF文件格式席赂,但是,由于使用了Android自己的linker时迫,因此颅停,和普通的Linux系統(tǒng)不完全兼容。

ELF是executable and Linking Format (可執(zhí)行連接格式)的縮寫(xiě)掠拳,最初由UNIX系統(tǒng)實(shí)驗(yàn)室發(fā)布癞揉,它是應(yīng)用程序二進(jìn)制接口(Application Binary Interface,ABI)的一部分。ELF 標(biāo)準(zhǔn)的目的是為軟件開(kāi)發(fā)人員提供一組二進(jìn)制接口定義烧董,這些接口可以在多種操作系統(tǒng)下生效毁靶,從而減少開(kāi)發(fā)的工作量。

ELF文件以節(jié)(Section)的方式組織在一起逊移,“節(jié)”描述了文件的各項(xiàng)信息预吆,例如代碼,數(shù)據(jù)胳泉,符號(hào)表拐叉,重定位表,全局偏移表等扇商。

可執(zhí)行文件裝載進(jìn)內(nèi)存時(shí)凤瘦,并不是被“完整”的映射進(jìn)內(nèi)存,而是根據(jù)ELF文件中格式的定義案铺,一段一段地裝載進(jìn)去蔬芥。因此,可執(zhí)行文件的格式和內(nèi)存的映象并不完全相同控汉,文件裝載進(jìn)內(nèi)存后是以‘段’的方式來(lái)組織的笔诵,如代碼段,數(shù)據(jù)段姑子,動(dòng)態(tài)段等噪径。

ELF格式的文件有3種:可執(zhí)行文件怪与,動(dòng)態(tài)庫(kù)(.so文件)和重定位(.o文件)逊躁。

這3中文件都有一個(gè)ELF頭屹徘,描述了整個(gè)可執(zhí)行文件的基本信息,如目標(biāo)代碼的格式沐旨,體系結(jié)構(gòu)森逮,各種段或節(jié)的偏移和大小等∠A可執(zhí)行文件和動(dòng)態(tài)庫(kù)中會(huì)有“程序頭部表(porgram Header Table)吊宋、但是,重定位文件中沒(méi)有程序頭部表颜武。此外璃搜。ELF文件中還會(huì)有一個(gè)“節(jié)區(qū)頭部表”(Section Header Table)? ,描述文件中各個(gè) 節(jié)區(qū)的內(nèi)容。這個(gè)表的內(nèi)容和程序頭部表的內(nèi)容有點(diǎn)重復(fù)鳞上,這是因?yàn)閮蓮埍淼挠猛静灰粯诱馕恰T诰幾g和鏈接階段(符號(hào)地址,不執(zhí)行庫(kù)文件)篙议。也就在可執(zhí)行文件的生成階段唾糯,需要使用“節(jié)區(qū)頭部表”怠硼,而可執(zhí)行文件裝載的時(shí)候使用的是程序頭部表。

分析ELF格式文件的目的移怯,是為了了解可執(zhí)行文件的裝載過(guò)程香璃,因此,下面重點(diǎn)介紹舟误,“程序頭部表”及其相關(guān)的數(shù)據(jù)結(jié)構(gòu)葡秒,對(duì)“節(jié)區(qū)頭部表”有興趣的讀取可以了解本節(jié)的內(nèi)容后自行分析。


3.5 圖

XXX.C---->GCC----xxx.ELF(此時(shí)使用節(jié)區(qū)頭部表)-----./(裝載時(shí)使用程序頭部表)------執(zhí)行

本節(jié)的內(nèi)容主要介紹32為可執(zhí)行文件額格式嵌溢,64位的格式除了一些字段的長(zhǎng)度不同外眯牧,文件的組織方式是一樣的。

ELF文件格式的數(shù)據(jù)結(jié)構(gòu)和常量的文件是exec_elf.h,位于目錄bionic/libc/include/sys下赖草。其中ELF頭定義如下:

typeof struct {

unsigned char e_ident[ELF_NIDENT] //目標(biāo)文件標(biāo)示

Elf32_Half e_type ; //目標(biāo)文件類(lèi)型

Elf32_Half e_machine学少; //目標(biāo)運(yùn)行平臺(tái)的體系結(jié)構(gòu)

Elf32_Word e_version; //目標(biāo)文件版本

Elf32_Addr e_entry; //程序的入口地址

Elf32_Off e_phoff; //程序頭部表的偏移量

Elf32_Off e_shoff; //節(jié)區(qū)頭部表的偏移量

Elf32_world e_flags; //文件相關(guān)的,特定于處理器的標(biāo)志秧骑。

Elf32_Half? e_ehsize; //ELF頭部的字節(jié)大小

Elf32_Half e_phentsize; //程序頭部表的表項(xiàng)的字節(jié)大小

Elf32_Half e_shentsize; //程序頭部表的表項(xiàng)數(shù)目

Elf32_Half e_shnum; //節(jié)區(qū)頭部表的表項(xiàng)的字節(jié)大小

Elf32_Half e_shstrndxl //節(jié)區(qū)頭部表的表項(xiàng)數(shù)目

} Elf32_Ehdr;

在程序頭部表里版确,最重要的是記錄“程序頭部表”和“節(jié)區(qū)頭部表”的位置,表示表項(xiàng)數(shù)目和表項(xiàng)大小的字段乎折。余下的字段中阀坏。

e_ident的16個(gè)字節(jié)標(biāo)明了ELF文件的標(biāo)志(7F+'E'+'L'+'F');

e_type表示文件類(lèi)型,2表示可執(zhí)行文件笆檀。

e_machine 表示機(jī)器類(lèi)別,3表示386機(jī)器盒至、8表示mips機(jī)器

e_entry表示程序的入口地址酗洒。

查看頭程序的文件readelf和objdump這兩個(gè)工具在prebuild目錄下有多份,分別對(duì)應(yīng)不同的平臺(tái)枷遂。在Android5.0的源碼里樱衷,可以使用的是目錄prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin下的工具

arm-eabi-readelf 有很多參數(shù)酒唉,其中-h參數(shù)能查看ELF文件的頭部信息矩桂,

程序頭部表

程序頭部表的作用是記錄文件中各種段的地址,大小等信息痪伦。在程序裝在和連接時(shí)都需要它侄榴。

程序頭部表示一個(gè)結(jié)構(gòu)Elf32_Phdr的數(shù)組,每個(gè)結(jié)構(gòu)中記錄了裝入內(nèi)存中的各個(gè)段的信息网沾,包括類(lèi)型癞蚕,地址,大小等辉哥。結(jié)構(gòu)Elf32_Phdr的定義如下:

typedef? struct{

Elf32_Word p_tpye; //段的類(lèi)型

Elf32_Off p_offset; //段的文件中的偏移

Elf32_Addr p_vaddr; //段裝入內(nèi)存后的虛擬地址

Elf32_Addr p_paddr; //端裝入內(nèi)存后的物理地址

Elf32_Word p_filesz; //段在文件中的大小

Elf32_Word p_memsz; //段裝入內(nèi)存后的大小

Elf32_Word p_flags; //段的標(biāo)志

Elf32_Word p_align; //內(nèi)存的對(duì)齊方式

} Elf32_Phdr;


同樣桦山,可以使用工具arm-eabi-readelf 來(lái)查看程序頭部表的信息攒射,這次需要使用的參數(shù)是"-l"

雖然“程序頭部表”可能包含多個(gè)段,但是恒水,只有類(lèi)型為"PT_LOAD"的“段”才會(huì)從文件映射到內(nèi)存中会放。其余類(lèi)型的"段"如果有實(shí)際的節(jié)區(qū),這些“節(jié)區(qū)”也會(huì)出現(xiàn)在"PT_LOAD"類(lèi)型的“段”中钉凌。

圖3.5中上半部分是程序頭部表咧最,可以看到它有8個(gè)“段”,圖3.5的下半部分是這些“段”包含的“節(jié)區(qū)”甩骏。這些段中只有兩個(gè)段的類(lèi)型是“PT_LOAD”,因此窗市,裝載這個(gè)文件時(shí),實(shí)際mmap進(jìn)內(nèi)存的也只有這兩個(gè)“段”饮笛。它們就是所謂的代碼段和數(shù)據(jù)段咨察,從它們的屬性也可以看出一個(gè)是“只讀”,另一個(gè)是“讀寫(xiě)”。

這兩個(gè)“PT_LOAD段"在圖3.5下半部分的對(duì)應(yīng)關(guān)系位于第02項(xiàng)和第03項(xiàng)福青,從圖3.5中可以看到他們包含了可執(zhí)行文件的所有"節(jié)區(qū)"摄狱。而DYNAMIC段(第04項(xiàng))只"包含"了一個(gè)".dynamic節(jié)區(qū)",這個(gè)"節(jié)區(qū)"和第03項(xiàng)中的".dynamic"是同一個(gè)无午。只不過(guò)".dynamic節(jié)區(qū)"的起始地址和大小等數(shù)據(jù)保存在“Dynamic段”中媒役,只能通過(guò)“DYNAMIC”段來(lái)找到“.dynamic”節(jié)區(qū),從而再找到“.plt”宪迟、“.dynsym”酣衷、“.got”等“節(jié)區(qū)”。相反次泽,雖然“PT_LOAD”類(lèi)型的“段”的地址空間范圍覆蓋了".dynmic節(jié)區(qū)"

但是無(wú)法通過(guò)它來(lái)找到“.dynamic節(jié)區(qū)”穿仪。這樣設(shè)計(jì)的目的是,當(dāng)系統(tǒng)裝在可執(zhí)行文件時(shí)只需要將"PT_LOAD"類(lèi)型的"段"完整的映射進(jìn)內(nèi)存就完成了意荤,而訪問(wèn)各個(gè)“節(jié)區(qū)”還是通過(guò)相應(yīng)的段所記錄的地址來(lái)完成啊片。


與重定位相關(guān)的"節(jié)區(qū)"的信息------DYNAMIC段

"DYNAMIC段"描述的是與重定位相關(guān)的"節(jié)區(qū)"的信息。"DYNAMIC段"也是個(gè)數(shù)組玖像,每項(xiàng)描述了"節(jié)區(qū)"的一些信息紫谷,一些復(fù)雜的"節(jié)區(qū)"需要好幾項(xiàng)來(lái)共同說(shuō)明,如".plt節(jié)區(qū)"就用了3項(xiàng)分別來(lái)描述"節(jié)區(qū)"的地址捐寥、大小笤昨、和"節(jié)區(qū)條目"的大小

“DYNAMIC段”的項(xiàng)數(shù)不是在文件的某個(gè)地方指定的,而是通過(guò)數(shù)組將最后一項(xiàng)的數(shù)據(jù)置為NULL來(lái)表示數(shù)組的結(jié)尾握恳。

typedef struct{

Elf32_Word d_tag;

union {

Elf32_Addr d_ptr;

Elf32_Word d_val;

}d_un;

} Elf32_Dyn;

其中咬腋,d_tag 表示每項(xiàng)的類(lèi)型。d_un是個(gè)聯(lián)合睡互,根據(jù)類(lèi)型使用根竿,器字段的作用是陵像。

d_val 表示一個(gè)整數(shù)值,根據(jù)d_tag的類(lèi)型不同有多種解釋寇壳,如偏移醒颖、尺寸等。

d_ptr 表示"節(jié)對(duì)象"的虛擬地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末壳炎,一起剝皮案震驚了整個(gè)濱河市泞歉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌匿辩,老刑警劉巖腰耙,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铲球,居然都是意外死亡挺庞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)稼病,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)选侨,“玉大人,你說(shuō)我怎么就攤上這事然走≡疲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵芍瑞,是天一觀的道長(zhǎng)晨仑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拆檬,這世上最難降的妖魔是什么寻歧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮秩仆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猾封。我一直安慰自己澄耍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布晌缘。 她就那樣靜靜地躺著齐莲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪磷箕。 梳的紋絲不亂的頭發(fā)上选酗,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音岳枷,去河邊找鬼芒填。 笑死呜叫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的殿衰。 我是一名探鬼主播朱庆,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼闷祥!你這毒婦竟也來(lái)了娱颊?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凯砍,失蹤者是張志新(化名)和其女友劉穎箱硕,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體悟衩,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡剧罩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了局待。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斑响。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钳榨,靈堂內(nèi)的尸體忽然破棺而出舰罚,到底是詐尸還是另有隱情,我是刑警寧澤薛耻,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布营罢,位于F島的核電站,受9級(jí)特大地震影響饼齿,放射性物質(zhì)發(fā)生泄漏饲漾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一缕溉、第九天 我趴在偏房一處隱蔽的房頂上張望考传。 院中可真熱鬧,春花似錦证鸥、人聲如沸僚楞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泉褐。三九已至,卻和暖如春鸟蜡,著一層夾襖步出監(jiān)牢的瞬間膜赃,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工揉忘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跳座,地道東北人端铛。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像躺坟,于是被迫代替她去往敵國(guó)和親沦补。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容