linux 解析elf文件格式,Linux下ELF文件解析

1. windows PE文件與Linux ELF文件概述

在windows中可執行文件是pe文件格式,Linux中可執行文件是ELF文件,其文件格式是ELF文件格式,在Linux下的ELF文件除了可執行文件(Excutable File),可重定位目標文件(RellocatableObject File)、共享目標文件(SharedObject File)、核心轉儲文件(CoreDump File)也都是ELF格式文件。

2.ELF文件結構分析

2.1 ELF文件查看

使用Linux下專用工具——readelf來查看elf文件信息

745491b04daa87040d8e5641b15e1758.png

查看readelf中的源碼

bd185ba19ee23c08723f7db97cb5a96c.png

一個典型的ELF文件大致的結構如下:

ELF文件大致的結構文件頭(ELF Header)

程序頭表(Program Header Table)

代碼段(.text)

數據段(.data)

bss段(.bss)

段表字符串表(.shstrtab)

段表(Section Header Table)

符號表(.symtab)

字符串表(.strtab)

重定位表(.rel.text)

重定位表(.rel.data)

2.2 FLF文件組成

2.2.1文件頭

用于記錄一個ELF文件的信息(多少位?能夠運行的CPU平臺是什么?程序的入口點在哪里)

查看ELF頭

806b53e0e08431e58fe6da0b96ba3c70.png

在readelf的源碼中變量類型Elf_Internal_Ehdr_,定義在internal頭文件中

#define

EI_NIDENT??????? 16??????????????? /* Size of e_ident[] */

typedef

struct elf_internal_ehdr {

unsigned char??????????????? e_ident[EI_NIDENT]; ??/* ELF "magic

number" */

bfd_vma??????????????? ??????e_entry;??????? ??????/* Entry point virtual address */

bfd_size_type??????????????? e_phoff;??????? ??????/* Program header table file offset */

bfd_size_type??????????????? e_shoff;??????? ??????/* Section header table file offset */

unsigned long??????????????? e_version;??????? ????/* Identifies object file version */

unsigned long??????????????? e_flags;??????? ??????/* Processor-specific flags */

unsigned short??????? ???????e_type;????????????? ?/* Identifies object file type */

unsigned short??????? ???????e_machine;??????? ????/* Specifies required architecture */

unsigned int ????????????????e_ehsize;??????? ?????/* ELF header size in bytes */

unsigned int ????????????????e_phentsize;????????? /* Program header table entry size */

unsigned int ????????????????e_phnum;

/* Program header table

entry count */

unsigned int ????????????????e_shentsize;??????? ???/* Section header table entry size */

unsigned int ????????????????e_shnum;

/* Section header table

entry count */

unsigned int ????????????????e_shstrndx;??????? ????/* Section header string table index */

}

Elf_Internal_Ehdr;

在Linux自帶的頭文件中查看,源碼文件頭的結構中一共有14個字段,對應到文件16進制中。

42822465e0c06c0ec2f1ef00dc27e7d7.png#define EI_NIDENT (16)?

typedef struct

{

unsigned char? ? ?e_ident[EI_NIDENT];? ? ? ? /* Magic number and other info */

Elf32_Half? ? ? ? e_type;? ? ? ? ? ? ? ? ? ? /* Object file type */

Elf32_Half? ? ? ? e_machine;? ? ? ? ? ? ? ? ?/* Architecture */

Elf32_Word? ? ? ? e_version;? ? ? ? ? ? ? ? ?/* Object file version */

Elf32_Addr? ? ? ? e_entry;? ? ? ? ? ? ? ? ? ?/* Entry point virtual address */

Elf32_Off? ? ? ? ?e_phoff;? ? ? ? ? ? ? ? ? ?/* Program header table file offset */

Elf32_Off? ? ? ? ?e_shoff;? ? ? ? ? ? ? ? ? ?/* Section header table file offset */

Elf32_Word? ? ? ? e_flags;? ? ? ? ? ? ? ? ? ?/* Processor-specific flags */

Elf32_Half? ? ? ? e_ehsize;? ? ? ? ? ? ? ? ? /* ELF header size in bytes */

Elf32_Half? ? ? ? e_phentsize;? ? ? ? ? ? ? ?/* Program header table entry size */

Elf32_Half? ? ? ? e_phnum;? ? ? ? ? ? ? ? ? ?/* Program header table entry count */

Elf32_Half? ? ? ? e_shentsize;? ? ? ? ? ? ? ?/* Section header table entry size */

Elf32_Half? ? ? ? e_shnum;? ? ? ? ? ? ? ? ? ?/* Section header table entry count */

Elf32_Half? ? ? ? e_shstrndx;? ? ? ? ? ? ? ? /* Section header string table index */

} Elf32_Ehdr;

2.2.2 程序頭表

記錄了每個Segment的相關信息,比如類型、對應文件的偏移、大小、屬性等。

程序頭表和段頭表相對獨立,它們是由ELF文件頭統一管理,程序頭表管理ELF文件加載后,ELF文件內可加載段到內存映像的映射關系,一般只有可執行文件中,包含程序頭表。程序頭表包含多個程序頭表項,程序頭表描述的對象稱為“Segment”,Segment描述的是ELF文件加載后的數據塊,段(Section)描述的是ELF文件加載前的數據塊。一般來說,來說兩者會存在一定的對應關系,比如代碼段.text的加載信息保存在程序頭表項對應存放代碼的Segment中,數據段.data的加載信息保存在程序頭表項對應存放數據的Segment中。有時候為了簡化程序頭表項的個數,會把同類型的多個段,設置整個ELF文件作為一個Segment。

f30a304feac32ff4fea33ed04e67c081.png

程序頭表的數據結構/* Program segment header.? */

typedef struct

{

Elf32_Word? ? ? ? p_type;? ? ? ? ? ? ? ? ?/* Segment type */

Elf32_Off? ? ? ? ?p_offset;? ? ? ? ? ? ? ?/* Segment file offset? Segment對應的內容在文件的偏移*/

Elf32_Addr? ? ? ? p_vaddr;? ? ? ? ? ? ? ? /* Segment virtual address Segment在內存中的線性地址*/

Elf32_Addr? ? ? ? p_paddr;? ? ? ? ? ? ? ? /* Segment physical address */

Elf32_Word? ? ? ? p_filesz;? ? ? ? ? ? ? ?/* Segment size in file */

Elf32_Word? ? ? ? p_memsz;? ? ? ? ? ? ? ? /* Segment size in memory */

Elf32_Word? ? ? ? p_flags;? ? ? ? ? ? ? ? /* Segment flags */

Elf32_Word? ? ? ? p_align;? ? ? ? ? ? ? ? /* Segment alignment */

} Elf32_Phdr;

#define? ? ? ? PT_NULL? ? ? ? ? ?0? ? ? ? ? ? ? ? /* Program header table entry unused */

#define? ? ? ? PT_LOAD? ? ? ? ? ?1? ? ? ? ? ? ? ? /* Loadable program segment */

#define? ? ? ? PT_DYNAMIC? ? ? ? 2? ? ? ? ? ? ? ? /* Dynamic linking information */

#define? ? ? ? PT_INTERP? ? ? ? ?3? ? ? ? ? ? ? ? /* Program interpreter */

#define? ? ? ? PT_NOTE? ? ? ? ? ?4? ? ? ? ? ? ? ? /* Auxiliary information */

#define? ? ? ? PT_SHLIB? ? ? ? ? 5? ? ? ? ? ? ? ? /* Reserved */

#define? ? ? ? PT_PHDR? ? ? ? ? ?6? ? ? ? ? ? ? ? /* Entry for header table itself */

#define? ? ? ? PT_TLS? ? ? ? ? ? 7? ? ? ? ? ? ? ? /* Thread-local storage segment */

#define? ? ? ? PT_NUM? ? ? ? ? ? 8? ? ? ? ? ? ? ? /* Number of defined types */

p_flag權限屬性標志

值 說明 宏1 可執行 PE_X

2 可寫 PE_W

3 可讀 PE_R

2.2.3 區段頭表

用于記錄ELF文件的主要的數據

查看區段

2bdda38a3de993e776c5692283289362.png

區段表頭的數據結構:

typedef struct

{

Elf32_Word sh_name; /* Section name (string tbl index) */

Elf32_Word sh_type; /* Section type */

Elf32_Word sh_flags; /* Section flags */

Elf32_Addr sh_addr; /* Section virtual addr at execution */

Elf32_Off sh_offset; /* Section file offset */

Elf32_Word sh_size; /* Section size in bytes */

Elf32_Word sh_link; /* Link to another section */

Elf32_Word sh_info; /* Additional section information */

Elf32_Word sh_addralign; /* Section alignment */

Elf32_Word sh_entsize; /* Entry size if section holds table */

} Elf32_Shdr;

區段頭表一共有10個字段,含義如下:

(1)sh_name段名,是一個是一個4字節的偏移,記錄了段名字符串在段表字符串表(“.shstrtab”段)內的偏移。段表字符串并非表的形式,而是一個文件塊,保存了所有的段表字符串內容,存儲在“.shstrtab”的段中,根據“.shstrtab”的偏移,加上sh_name便可以訪問到每個段對應的段名字符串。

56ba12df45fcb95f13edb7bf08aa082e.png

04644caa60e3cfe0cc319fdba3ada402.png

起始地址是000017ac,第一個段表項全0,sh_name在段表項中的偏移是001b,由上圖可以得到“.shstrtab”段的偏移是0016ae,

所以,計算段名的偏移應該是0x0000001b+ 0x000016ae = 0x000016c9

根據計算的結果,查看0x000016c9處:

c8b51948461f8178eb161b9079397ff2.png

(2)sh_type,表示段的類型。段的類型有很多,常見的有SHT_PROGBITS,表示程序數據,SHT_SYMTAB表示符號表,SHT_STRTAB表示字符串表,還有專門存放構造函數數組段SHT_INIT_ARRAY,析構函數數組段SHT_FINI_ARRAY。

a? ?.txt 代碼段

b? ?.data 數據段

c? ?.radata記錄常量數據

d? ?.symtab記錄符號表(相當于PE文件的導出表)的數據

e? ?.strtab 串表段

f? ?.shstrtab 有段表 字符串表段

g? ?.rel .plt記錄某個區段的重定位內容(相當于PE文件的導入表)

對應的宏如下:

/* Legal values for sh_type (section type).? */

#define SHT_NULL? ? ? ? ? ? ? 0? ? ? ?/* Section header table entry unused */

#define SHT_PROGBITS? ? ? ? ? 1? ? ? ?/* Program data */

#define SHT_SYMTAB? ? ? ? ? ? 2? ? ? ?/* Symbol table */

#define SHT_STRTAB? ? ? ? ? ? 3? ? ? ?/* String table */

#define SHT_RELA? ? ? ? ? ? ? 4? ? ? ?/* Relocation entries with addends */

#define SHT_HASH? ? ? ? ? ? ? 5? ? ? ?/* Symbol hash table */

#define SHT_DYNAMIC? ? ? ? ? ?6? ? ? ?/* Dynamic linking information */

#define SHT_NOTE? ? ? ? ? ? ? 7? ? ? ?/* Notes */

#define SHT_NOBITS? ? ? ? ? ? 8? ? ? ?/* Program space with no data (bss) */

#define SHT_REL? ? ? ? ? ? ? ?9? ? ? ?/* Relocation entries, no addends */

#define SHT_SHLIB? ? ? ? ? ? ?10? ? ? /* Reserved */

#define SHT_DYNSYM? ? ? ? ? ? 11? ? ? /* Dynamic linker symbol table */

#define SHT_INIT_ARRAY? ? ? ? 14? ? ? /* Array of constructors */

#define SHT_FINI_ARRAY? ? ? ? 15? ? ? /* Array of destructors */

#define SHT_PREINIT_ARRAY? ? ?16? ? ? /* Array of pre-constructors */

(3)sh_flags,表示段標志,記錄段的屬性。其中0表示默認屬性,1表示段可寫,取值位SHF_WRITE。2表示段加載后需要為之分配內存空間,取值為SHF_ALLOC。4表示可執行,取值為SHF_EXECINSTR,段標志屬性可以疊加。

(4)sh_addr,表示段加載后的線性地址

(5)sh_offset,表示段在文件內的偏移,根據此偏移可確定段的位置,讀取段的內容。

(6)sh_size,表示段的大小,單位為字節。需要注意的是,如果段類型為SHT_NOBITS,段內沒有數據,那么段的大小并非指文件塊的大小,而是指段加載后占用內存的大小。

27419630f1fdd45c602e1d92184c21d6.png

(7~8)sh_link和sh_info表示段的鏈接信息,一般用于描述符號表段和重定位表段的鏈接信息。對于符號表段(SHT_SYMTAB),sh_link記錄的是符號表使用的串表所在段(一般是,.strtab)對應段表項在段表內的索引。

5461ebe004834732c52c8d19349399f2.png

sh_info記錄的是符號表最后一個局部符號的符號表項在符號表內的索引加1,一般恰好是第一個全局符號的符號表項索引,這樣可以幫助連接器更快的地定位到第一個全局符號。如下圖:段中符號表段的信息sh_info,剛好是局部符號+1的索引。

c8bd678e49824e43c3cbc6d1e4907894.png

對于重定位表表段(段類型是SHT_REL),sh_link記錄重定位所作用的符號表段表項早段內的索引,而sh_info記錄重定位所作用的段對應的段表項在段表中的索引。

6e624e51c03d1018ae59f052a960833a.png

sh_type sh_link sh_infoSHT_DYNAMIC 此表項中條目所用到的字符串表在段表中的索引

SHT_HASH 此哈希表所適用的符號表的段表索引

SHT_REL 相關符號表的段表索引 重定位所使用的段的段表索引

SHT_RELA 相關聯的字符串表的段表索引 最后一個局部符號的符號表索引值+1

其它 SHN_UNDEF 0

(9)sh_addralign,表示段的對齊方式,對齊規則為 sh_offset %sh_addralign = 0,即段的文件偏移必須是sh_addralign的整數倍,sh_addralign的取值必須是2的整數倍,入1、2、4、8等。

對齊值 對齊方式 說明0 無對齊要求

1 無對齊要求

4 對齊4 滿足sh_iffset % 4 = 0

16 對齊16 滿足sh_iffset % 16 = 0

32 對齊32 滿足sh_iffset % 32 = 0

3559489fa2c54d20b767b210903a7ab1.png

(10) sh_entsize,一般用于保存注入符號表段,重定位表段時,表示段內保存表的表項大小。例如符號表段“.symtab”內保存的符號表的表項大小為sizeof(Elf32_sym)= 16字節,重定位表段“.rel.plt”內保存的重定位表的表項大小為sizeof(Elf32_rel)= 8字節。

2.2.4 ELF符號表(Symbol Table)

ELF文件的符號表保存了程序中的符號信息,包括程序中的文件名、函數名、全局變量名等,符號表一般保存在名為“.strtab”的段內,該段對應段表項的類型為SHT_SYMTAB。符號表包含多個符號表項,每個符號表項記錄了符號的名稱、位置、類型等信息。

符號表象的數據結構:typedef struct

{

Elf32_Word st_name; /* Symbol name (string tbl index) */

Elf32_Addr st_value; /* Symbol value */

Elf32_Word st_size; /* Symbol size */

unsigned char st_info; /* Symbol type and binding */

unsigned char st_other; /* Symbol visibility */

Elf32_Section st_shndx; /* Section index */

} Elf32_Sym;

0200226d57198c995d2e10487b011f13.png

2.2.5 ELF重定位表(Reloc Table)

重定位表常見于可重定位目標文件內,對于靜態鏈接生成的可可執行文件,一般不包括重定位表,動態鏈接生成的可執行文件暫時不討論。重定位表一般保存在以名為“.rel”開頭的段內,該段對應段表項的類型為SHT_REL,ELF文件需要重定位的段,一般都對應一個重定位表,比如代碼段“.txt”的重定位表保持在“.rel.text”內,數據段“.data”的重定位表保持在“.rel.data”內。

重定位表包含多個重定位表項,每個重定位表項記錄一條重定位信息,包括重定位的符號、位置、類型等。

/* Relocation table entry without addend (in section of type SHT_REL). */

typedef struct

{

Elf32_Addr r_offset; /* Address */

Elf32_Word r_info; /* Relocation type and symbol index */

} Elf32_Rel;

b73e5dcfc32be1bd83e67dfc8f52cc70.png

2.2.6 ELF串表(String Table)

ELF文件內的段表和符號表需要記錄段名和符號名,這些名稱都是字符串。然而,段表項和符號表項都是固定長度的數據結構,無法存儲不定長的字符串。因此FLE文件將名稱字符串內容集中存放在一個段內,稱為串表。這些段表項和符號表項只需記錄段名字符串或符號名字符串在對應串表項的位置即可。

雖然存儲的字符串表的內容稱為串表,但是并非表的形式,而是一個文件區域。

645294af3af7fcfa983ba4bbcb2f79fa.png

-End-

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396173.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396173.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396173.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

富爸爸窮爸爸害了我_這是我必須告訴爸爸的-在我們的時間用完之前

富爸爸窮爸爸害了我by Bram Bos通過Bram Bos 這是我必須告訴爸爸的-在我們的時間用完之前 (This is what I must tell my dad — before our time runs out) I was a young boy in the 1980s. Like the typical Generation-X kid, I grew up in the days of the home computer…

應用容器公共免費部署平臺

從網上信息,發現了一個公共的容器部署平臺 openshift.com,可以將我們封裝好的docker鏡像部署到平臺上, 這樣就不需要擁有一臺云服務器了。對于測試環境非常有用。 首先當然是需要注冊。這里全英文 第二,注冊之后需要選擇你想要的套…

西門子rwd68溫控器說明書_西門子RWD68說明書

西門子RWD68說明書顯示第一界面Y1XX模擬量輸出電壓值YIXX傳感器此時實際溫度;同時按—鍵五秒顯示第二界面PS4主控制回路參數;按—鍵顯示第三界面PS3輔助回路參數但僅在室外補償時出現;按—鍵顯示第四界面PS2按—鍵顯示第五界面PS1控制曲線運用…

linux 內存管理優化,Linux性能優化實戰 內存篇 閱讀筆記

第十五講 基礎篇:Linux內存是怎么工作的(2020.6.8)這一講相關的內容正好之前看csapp的時候總結了一下,可以直接貼出來作為總結了。Linux的內存工作原理,這又是一個特別大的話題。一切向著盡量利用物理資源的方向在發展,在沒有虛擬…

傅里葉變換與大數乘法

我們知道,兩個 N 位數字的整數的乘法,如果使用常規的算法,時間復雜度是 O(N2)。然而,使用快速傅里葉變換,時間復雜度可以降低到 O(N logN loglogN)。 假設我們要計算以下兩個 N 位數字的乘積: a (aN-1aN-2…

idea 啟動界面導入項目_如何為您的項目啟動有效的登錄頁面

idea 啟動界面導入項目by Christian-Peter Heimbach通過克里斯蒂安彼得海姆巴赫 如何為您的項目啟動有效的登錄頁面 (How to launch an effective landing page for your project) I began my career 10 years ago doing online marketing and advertising for video games. S…

linux程序已經在后臺運行凍結了_如何使程序在Linux后臺運行

經常在Linux上面運行程序都有這樣的體驗:某個程序運行的時候,會產生大量的log(提示)信息,但實際上我們只想讓它跑一下而已,log暫時不需要或者后面才有需要。同時run多個相同或者不同程序的時候,占了好多的命令行界面&a…

數字時代的精益組織

精益IT應該幫助簡化和改善我們為客戶創造價值的方式,并提出面向未來的更好的解決方案。未來的組織將專注于同行業的產品或業務流——其他的一切,包括專家和管理者在內,都是為了讓一線工作人員可以第一時間就做好,而又不會遇到任何…

9th week blog

1、第一個計算機語言:Fortran Fortran I誕生于1957年,由IBM設計,是世界上第一個真正的計算機語言。 Fortran I運行于IBM 704計算機上。 Fortran I支持:變量(變量名最多6個字符)、If和do語句、格式化IO。 不…

cas單點登錄系統:客戶端(client)詳細配置(包含統一單點注銷配置)

最近一直在研究cas登錄中心這一塊的應用,分享一下記錄的一些筆記和心得。后面會把cas-server端的配置和重構,另外還有這幾天再搞nginxcas的https反向代理配置,以及cas的證書相關的知識分享出來。 Cas由兩部分組成,Cas Server和Cas…

open 端口打開Linux,linux – nmap顯示打開的端口,但netstat沒有

如果我使用nmap掃描我的服務器,則表明已打開21端口.但是當我登錄到這個服務器并運行netstat時,我什么也看不見.$nmap -sT serverStarting Nmap 4.76 ( http://nmap.org ) at 2009-06-24 11:54 MSDInteresting ports on server (x.x.x.x):Not shown: 994 filtered portsPORT STA…

技能學習重要的古語_學習方法:最重要的開發人員技能

技能學習重要的古語by Preethi Kasireddy通過Preethi Kasireddy 學習方法:最重要的開發人員技能 (Learning How to Learn: The Most Important Developer Skill) Being an efficient learner is at least as important as being an efficient coder.成為高效的學習…

Git submodule 的筆記

這次不造輪子,寫寫文章。file最近想把自己的 blog 整理到 github 上,但由于其中依賴了一些主題以及插件,這時候 git submodule 就能很好的處理這種情況了。 submodule 是什么? submodule 顧名思義,子模塊。在一個項目依…

Leetcode690.Employee Importance員工的重要性

給定一個保存員工信息的數據結構,它包含了員工唯一的id,重要度 和 直系下屬的id。 比如,員工1是員工2的領導,員工2是員工3的領導。他們相應的重要度為15, 10, 5。那么員工1的數據結構是[1, 15, [2]],員工2的數據結構是…

linux進程管理類命令大全,Linux進程管理類命令

一、htop命令選項-d #:指定延遲時間間隔;-u UserName:僅顯示指定用戶的進程;-s COLUME:以指定字段進行排序;子命令:l:顯示選定的進程打開的文件列表;s:跟蹤選…

C#操作Excel

1.System.Data.DataTable連接數據庫 ExcelFile 是excel的完整路徑//OleDbConnection conExcel new OleDbConnection("ProviderMicrosoft.Jet.OLEDB.4.0;Data Source" ExcelFile ";Extended PropertiesExcel 8.0");//if (conExcel.State ConnectionStat…

android抓包工具——使用fiddler4在安卓手機抓包

Fiddler是一款非常流行并且實用的http抓包工具,它的原理是在本機開啟了一個http的代理服務器,然后它會轉發所有的http請求和響應,因此,它比一般的firebug或者是chrome自帶的抓包工具要好用的多。不僅如此,它還可以支持…

rust風化速度_反駁《Golang、Rust的執行速度的對照,讓人大吃一驚。》——不會別瞎說...

首先我無意引戰,但是今天看到某位同學的文章里有某些錯誤,不得不指正一下。1. 測量時間的時候我們使用 std::time::SystemTime::elapsed 即可,不必蹩腳的使用兩個 system 輸出出來還得手動算一下。(當然你說對Rust不熟也就無所謂了)2. 最重要…

css flexbox模型_代碼簡介:CSS Flexbox有點像旅行

css flexbox模型Here are three stories we published this week that are worth your time:這是我們本周發布的三個值得您關注的故事: CSS Flexbox explained by road tripping across the country: 7 minute read CSS Flexbox在全國各地的旅途中進行了解釋&#…

Sharepoint 2013設置customErrors

原文地址:http://www.cnblogs.com/renzh/archive/2013/03/05/2944309.html#3407239 一、首先設置IIS中的Web.config文件 找到對應的IIS應用程序目錄,如:C:\inetpub\wwwroot\wss\VirtualDirectories\3000 在此文件夾下包含一個web.config文件&…