无限期停更
ELF文件格式分析 | Sp4n9x’s Blog

手拆ELF32(一,文件头)【转】 - Sky&Zhang - 博客园 (cnblogs.com)

ELF解析01 - ELF头和程序头 - 掘金 (juejin.cn)

ELF Section Header的结构 (mudongliang.github.io)

因为上面几篇讲的太详细了,后面不写了

其中第三篇为加载时需要关注的点,前两篇都是讲结构特点


上次了解了windows系统上的PE文件结构,这里在网上总结了一些(抄了一些)内容

ELF分为大致分为三种:

  • 可重定位文件(relocatable):编译器和汇编器产生的.o文件,被Linker所处理
  • 可执行文件(executable):Linker对.o文件进行处理输出的文件,进程映像
  • 共享对象文件(shared object):动态库文件.so

文件布局大致为:

  • ELF header
  • program header table(描述段)
  • 段和区
  • section header table(描述区)

以上的布局只有ELF header在固定位置,其它的位置不定

ELF header

e_ident

Magic Number 7F 45 4C 46

EI_class:(1字节)

  • 无效类
  • 1 32位
  • 2 64位

EI_DATA:(1字节)

  • 0 无效数据编码
  • 1 小端序
  • 2 大端序

EI_VERSION:只有01这个值

EI_OSABI:操作系统/ABI标识

宏名称 含义
ELFOSABI_NONE 0 No extensions or unspecified
ELFOSABI_SYSV 0 UNIX System V ABI
ELFOSABI_HPUX 1 HP-UX ABI
ELFOSABI_NETBSD 2 NetBSD ABI
ELFOSABI_LINUX 3 Linux ABI
ELFOSABI_HURD 4 GNU Hurd ABI
ELFOSABI_SOLARIS 6 Sun Solaris ABI
ELFOSABI_AIX 7 IBM AIX ABI
ELFOSABI_IRIX 8 SGI Irix ABI
ELFOSABI_FREEBSD 9 FreeBSD ABI
ELFOSABI_TRU64 10 Compaq TRU64 UNIX ABI
ELFOSABI_MODESTO 11 Novell Modesto ABI
ELFOSABI_OPENBSD 12 OpenBSD ABI
ELFOSABI_OPENVMS 13 OpenVMS ABI
ELFOSABI_NSK 14 NonStop Kernel ABI
ELFOSABI_AROS 15 AROS ABI
ELFOSABI_FENIXOS 16 Fenix OS ABI
ELFOSABI_CLOUDABI 17 CloudABI
ELFOSABI_ARM_AEABI 64 ARM EABI
ELFOSABI_ARM 97 ARM ABI
ELFOSABI_STANDALONE 255 Standalone (embedded) application

EI_ABIVERSION:

进一步指定ABI版本

elf pad:填充字节,置0

E_TYPE

标明文件类型(2字节)

宏名称 含义
ET_NONE 0 无文件类型
ET_REL 1 可重定位文件
ET_EXEC 2 可执行文件
ET_DYN 3 共享目标文件
ET_CORE 4 核心转储文件
ET_NUM 5 定义的文件类型数量
ET_LOOS 0xFE00 特定操作系统目标文件类型值范围的下限
ET_HIOS 0xFEFF 特定操作系统目标文件类型值范围的上限
ET_LOPROC 0xFF00 特定处理器目标文件类型值范围的下限
ET_HIPROC 0xFFFF 特定处理器目标文件类型值范围的上限

e_machine

标明处理器架构和指令集(2字节)

宏名称 含义
EM_NONE 0 无机器类型
EM_M32 1 AT&T WE 32100
EM_SPARC 2 SUN SPARC
EM_386 3 Intel 80386(x86)
EM_68K 4 Motorola 68000(M68k)
EM_88K 5 Motorola 88000(M88k)
EM_860 7 Intel 80860
EM_MIPS 8 MIPS R3000 big-endian
EM_MIPS_RS3_LE 10 MIPS R3000 little-endian
EM_MIPS_RS4_BE 10 MIPS R4000 big-endian
EM_PPC 20 PowerPC
EM_PPC64 21 PowerPC 64-bit
EM_ARM 40 ARM 32-bit(up to ARMv7/Aarch32)
EM_SPARCV9 43 SPARC v9 64-bit
EM_IA_64 50 HP/Intel IA-64
EM_X86_64 62 AMD x86-64
EM_MSP430 105 Texas Instruments msp430
EM_ALTERA_NIOS2 113 Altera Nios II
EM_AARCH64 183 ARM 64-bit(ARMv8/Aarch64)
EM_AVR32 185 Amtel 32-bit microprocessor
EM_STM8 186 STMicroelectronics STM8
EM_RISCV 243 RISC-V
EM_BPF 247 Linux BPF – in-kernel virtual machine

e_version

当前文件版本(四字节)

0 无版本

其它 当前版本号

程序入口

8字节,标明入口点

程序头表偏移

8字节,描述段表在文件中的偏移

区表偏移

8字节,描述区表在文件中的偏移

e_flag

处理器指定的与文件相关联的flag(4字节,一般是0)

ELF_header 大小

2字节,指明头大小。一般为0x40

程序头表大小

2字节,如果没有程序头表,则为0

程序头内容数量

2字节,标明程序头表中的内容个数

节区头表大小

2字节,如果没有节区头表,则为0

节区头内容数量

2字节,标明节区头表中的内容个数

节区头字符表索引

2字节,有以下可选值

/* Special section indices. */

#define SHN_UNDEF 0 /* Undefined section /
#define SHN_LORESERVE 0xff00 /
Start of reserved indices /
#define SHN_LOPROC 0xff00 /
Start of processor-specific /
#define SHN_BEFORE 0xff00 /
Order section before all others
(Solaris). /
#define SHN_AFTER 0xff01 /
Order section after all others
(Solaris). /
#define SHN_HIPROC 0xff1f /
End of processor-specific /
#define SHN_LOOS 0xff20 /
Start of OS-specific /
#define SHN_HIOS 0xff3f /
End of OS-specific /
#define SHN_ABS 0xfff1 /
Associated symbol is absolute /
#define SHN_COMMON 0xfff2 /
Associated symbol is common /
#define SHN_XINDEX 0xffff /
Index is in extra table. /
#define SHN_HIRESERVE 0xffff /
End of reserved indices */

program_header_table

是一个结构体数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define PN_XNUM		0xffff

typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
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;

typedef struct
{
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
} Elf64_Phdr;

段类型

p_type,四字节

宏名称 含义
PT_NULL 0 该数组元素未使用。除p_type外,其他结构体成员的值都是未定义的。这种类型可以使程序头表(Program Header Table)忽略此条目。
PT_LOAD 1 此类型段为一个可加载的段,大小由p_filesz和p_memsz描述。文件中该段的内容被映射到相应内存段的开始处。如果p_memsz大于p_filesz,“剩余”的字节都要被置为0并跟踪段的初始化区域。p_filesz不能大于p_memsz。可加载的段在程序头表中按照p_vaddr升序排列。
PT_DYNAMIC 2 此类型段给出动态链接信息,具体参见ELF手册Book III。
PT_INTERP 3 此类型段给出了一个以Null结尾的字符串的位置和长度,该字符串将被当作解释器的路径名进行调用。这种段类型仅对可执行文件有意义(也可能出现在共享目标文件中)。此外,这种段在一个文件中最多出现一次。而且该段类型的数组元素存在的话,它必须在所有可加载段条目的前面。
PT_NOTE 4 此类型段给出附加信息的位置和大小。
PT_SHLIB 5 该段类型被保留,不过语义未指定。而且,包含这种类型数组元素的程序不符合Unix System V的ELF标准,具体参见ELF手册Book III。
PT_PHDR 6 该段类型的数组元素如果存在的话,则给出了程序头表自身在文件和程序内存映像中的的位置和大小。此类型的段在文件中最多出现一次。此外,只有程序头表是程序内存映像的一部分时,该段类型的数组元素才会存在。如果该段类型的数组元素存在,则必须在所有可加载段条目的前面。
PT_TLS 7 该段类型的数组元素给出线程本地存储段(TLS)的信息。
PT_LOOS 0x60000000 特定操作系统段类型值的下限。
PT_GNU_EH_FRAME 0x6474E550 该段类型数组元素指定异常处理信息的位置和大小(由.eh_frame_hdr节定义)[^5]。
PT_GNU_STACK 0x6474E551 该段类型数组元素中的p_flags成员指定包含栈的段的权限,并用于指示栈是否应该是可执行的。没有此段类型的数组元素,则表示该栈将是可执行的[^5]。
PT_GNU_RELRO 0x6474E552 该段类型数组元素指定了一个在重定位后可以被置为只读的段的位置和大小[^5]。
PT_GNU_PROPERTY 0x6474E553 该段类型数组元素指定.note.gnu.property节的位置和大小。
PT_HIOS 0x6FFFFFFF 特定操作系统段类型值的上限。
PT_LOPROC 0x70000000 特定处理器段类型值的下限。
PT_HIPROC 0x7FFFFFFF 特定处理器段类型值的上限。

段权限

p_flags,四字节

宏名称 含义
PF_X 0x1 段具有可执行权限
PF_W 0x2 段具有写权限
PF_R 0x4 段具有读权限
PF_MASKOS 0x0FF00000 为特定操作系统预留
PF_MASKPROC 0xF0000000 为特定处理器预留

如果是0,表明拒绝访问
以上权限可组合,且一般情况,段没有写权限

宏名称 准确的权限 允许的权限
none 0 拒绝所有访问 拒绝所有访问
PF_X 1 只执行 读,执行
PF_W 2 只写 读,写,执行
PF_W + PF_X 3 写,执行 读,写,执行
PF_R 4 只读 读,执行
PF_R + PF_X 5 读,执行 读,执行
PF_R + PF_W 6 读,写 读,写,执行
PF_R + PF_W + PF_X 7 读,写,执行 读,写,执行

段内容

Segment Contents标明了一个段的多种节的类型

段偏移

在文件中的偏移,8字节

段虚拟地址

表示加载后的相对偏移。真实地址=虚拟地址基址+段虚拟地址,8字节

段物理地址

不知道作用,可能是在虚拟内存中的地址。8字节

段文件长度

段在文件中的长度,8字节

段虚拟长度

段在内存中的长度,8字节

段对齐方式

8字节,一般为4096


参考:

ELF 标识 - 链接程序和库指南 (oracle.com)