IzayoiShiki
ELF文件格式

ELF文件格式

ELF文件格式

摘抄自CTF Wiki

image-20240521143833953

ELF Header:给出整个文件的组织情况

Program Header Table:向系统描述如何创建进程,重定位文件不需要,但是用于生成进程的目标文件必须具有

Section:包含了链接视图中要使用的大部分信息:如指令/数据/符号表/重定位信息等

Section Header Table:包含了描述文件节区的信息,每个节区在表中都有一个表项,会给出节区名称、节区大小等信息

ELF Header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define EI_NIDENT   16

typedef struct {
unsigned char e_ident[EI_NIDENT];
ELF32_Half e_type;
ELF32_Half e_machine;
ELF32_Word e_version;
ELF32_Addr e_entry;
ELF32_Off e_phoff;
ELF32_Off e_shoff;
ELF32_Word e_flags;
ELF32_Half e_ehsize;
ELF32_Half e_phentsize;
ELF32_Half e_phnum;
ELF32_Half e_shentsize;
ELF32_Half e_shnum;
ELF32_Half e_shstrndx;
} Elf32_Ehdr;

e_ident

占八个字节,每个字节作用如下

image-20240521222723276

EI_MAG

magic头,表示是ELF文件

image-20240522000610981

EI_CLASS

标识文件的类型

image-20240522000723847

EI_DATA

表示文件的编码类型

image-20240522000809244

e_type

image-20240522004114244

e_machine

指定了当前文件可以运行的机器架构

image-20240522012513320

e_version

标识目标文件的版本

image-20240522013025463

e_entry

这一项为系统转交控制权给 ELF 中相应代码的虚拟地址。如果没有相关的入口项,则这一项为 0

e_phoff

这一项给出程序头部表在文件中的字节偏移(Program Header table OFFset)。如果文件中没有程序头部表,则为 0

e_shoff

这一项给出节头表在文件中的字节偏移( Section Header table OFFset )。如果文件中没有节头表,则为 0

e_flags

这一项给出文件中与特定处理器相关的标志,这些标志命名格式为EF_machine_flag

e_ehsize

给出 ELF 文件头部的字节长度(ELF Header Size)

e_phentsize

这一项给出程序头部表中每个表项的字节长度(Program Header ENTry SIZE)。每个表项的大小相同

e_phnum

这一项给出程序头部表的项数( Program Header entry NUMber )。因此,e_phnume_phentsize 的乘积即为程序头部表的字节长度。如果文件中没有程序头部表,则该项值为 0

e_shentsize

这一项给出节头的字节长度(Section Header ENTry SIZE)。一个节头是节头表中的一项;节头表中所有项占据的空间大小相同

e_shnum

这一项给出节头表中的项数(Section Header NUMber)。因此, e_shnume_shentsize 的乘积即为节头表的字节长度。如果文件中没有节头表,则该项值为 0

e_shstrndx

这一项给出节头表中与节名字符串表相关的表项的索引值(Section Header table InDeX related with section name STRing table)。如果文件中没有节名字符串表,则该项值为SHN_UNDEF

Program Header Table

Program Header Table 是一个结构体数组,每一个元素的类型是 Elf32_Phdr,描述了一个段或者其它系统在准备程序执行时所需要的信息。其中,ELF 头中的 e_phentsizee_phnum 指定了该数组每个元素的大小以及元素个数。一个目标文件的段包含一个或者多个节。

Elf32_Phdr

1
2
3
4
5
6
7
8
9
10
typedef struct {
ELF32_Word p_type;
ELF32_Off p_offset;
ELF32_Addr p_vaddr;
ELF32_Addr p_paddr;
ELF32_Word p_filesz;
ELF32_Word p_memsz;
ELF32_Word p_flags;
ELF32_Word p_align;
} Elf32_Phdr;

image-20240522203308466

段的类型

image-20240522204044876

p_flags

当系统为可加载的段创建内存镜像时,它会按照 p_flags 将段设置为对应的权限

image-20240522220450287

其中,所有在 PF_MASKPROC 中的比特位都是被保留用于与处理器相关的语义信息

image-20240522221137140

段的内容

一个段可能包括一到多个节区,但是这并不会影响程序的加载。尽管如此,我们也必须需要各种各样的数据来使得程序可以执行以及动态链接等等。下面会给出一般情况下的段的内容。对于不同的段来说,它的节的顺序以及所包含的节的个数有所不同。此外,与处理相关的约束可能会改变对应的段的结构。

image-20240523002338828

image-20240523002343766

程序头部的 PT_DYNAMIC 类型的元素指向 .dynamic 节。其中,got 表和 plt 表包含与地址无关的代码相关信息。尽管在这里给出的例子中,plt 节出现在代码段,但是对于不同的处理器来说,可能会有所变动。

.bss 节的类型为 SHT_NOBITS,这表明它在 ELF 文件中不占用空间,但是它却占用可执行文件的内存镜像的空间。通常情况下,没有被初始化的数据在段的尾部,因此,p_memsz 才会比 p_filesz

Section Header Table

在ELF文件尾部,用于定位ELF文件中的每个Section的具体位置

ELF Header中的e_shoff项给出了从文件开头到Section Header Table的偏移,e_shnum提供了Section Header Table的项数,e_shentsize提供了每一项的字节大小

Section Header Table是一个结构体数组,每个元素的类型是ELF32_shdr

ELF32_shdr

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct {
ELF32_Word sh_name;
ELF32_Word sh_type;
ELF32_Word sh_flags;
ELF32_Addr sh_addr;
ELF32_Off sh_offset;
ELF32_Word sh_size;
ELF32_Word sh_link;
ELF32_Word sh_info;
ELF32_Word sh_addralign;
ELF32_Word sh_entsize;
} Elf32_Shdr;

image-20240523155329324

索引为0的节区头

image-20240523155905747

特殊下标

image-20240523162755386

系统保留在SHN_LORESERVESHN_HIRESERVE之间 (包含边界) 的索引值,这些值不在节头表中引用。也就是说,节头表不包含保留索引项。

sh_type

image-20240523183951810

image-20240523184003588

sh_flags

sh_flags 字段的每一个比特位都可以给出其相应的标记信息,其定义了对应的节区的内容是否可以被修改、被执行等信息。如果一个标志位被设置,则该位取值为 1,未定义的位都为 0

image-20240523184039886

sh_link & sh_info

根据sh_type改变

image-20240523184106055

Author:IzayoiShiki
Link:http://izayoishiki.github.io/2024/05/24/ELF文件格式/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可