0x01 介绍
ELF(Executable and Linkable Format)是一种常见的可执行文件和共享库格式,其结构如下:
- ELF header:包含了 ELF 文件的基本属性信息。
- Program header table:描述了程序在内存中的加载情况,包括可执行代码段、数据段等。
- Section header table:描述了 ELF 文件中所有节区的信息,如代码节区、数据节区等。
- 节区数据:包含了 ELF 文件中的实际数据,如代码、数据等。
ELF 文件的结构可以根据不同的操作系统和体系结构而有所差异。
0x02 ELF header
在 /usr/include/elf.h
或ELF规范里可以查到ELF头部的定义:
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* 幻数及其他信息 */
Elf64_Half e_type; /* 对象文件类型 */
Elf64_Half e_machine; /* 架构 */
Elf64_Word e_version; /* 对象文件版本 */
Elf64_Addr e_entry; /* 程序入口虚拟地址 */
Elf64_Off e_phoff; /* 程序头表的偏移量 */
Elf64_Off e_shoff; /* 节头表的偏移量 */
Elf64_Word e_flags; /* 保存与文件相关的、特定于处理器的标志 */
Elf64_Half e_ehsize; /* ELF头部的大小 */
Elf64_Half e_phentsize; /* 程序头表的条目大小 */
Elf64_Half e_phnum; /* 程序头表的条目数 */
Elf64_Half e_shentsize; /* 节头表的条目大小 */
Elf64_Half e_shnum; /* 节头表的条目数 */
Elf64_Half e_shstrndx; /* 节头表中与节名称字符串相关联的条目的索引 */
} Elf64_Ehdr;
ELF header包含以下部分:
标识信息 (e_ident)
包括ELF文件类型、机器架构、版本等信息。
e_ident数组始终以4个字节的幻数为开头,以此来标识ELF文件,幻数由十六进制0x7f和ELF的ASCII码组成。
幻数后面的字节提供了有关ELF二进制文件类型规范的详细信息,后面那些字节的索引分别称为EI_CLASS、EI_DATA、EI_VERSION、EI_OSABI、EI_ABIVERSION以及EI_PAD等
- EI_CLASS标识该二进制文件用于32位还是64位体系结构,前者设置为常量ELFCLASS32(1),后者设置为常量ELFCLASS64(2)
- EI_DATA标识架构的字节序,也就是多字节值是大端序还是小端序,ELFDATA2LSB(1)表示小端序,ELFDATA2MSB(2)表示大端序
- EI_VERSION标识ELF规范版本,现在只有一个值EV_CURRENT也就是1
- EI_OSABI和EI_ABIVERSION标识关于应用程序二进制接口和操作系统的信息
- EI_PAD包含多个字节,保留为了以后使用
readelf可以查看ELF头
e_type、e_machine和e_version
文件类型 (e_type)
描述ELF文件的类型,如可执行文件、共享库、目标文件等。
机器架构 (e_machine)
描述ELF文件所使用的机器架构,例如x86、ARM等。
版本信息 (e_version)
描述ELF头部和节头表的版本号。
入口地址 (e_entry)
描述可执行文件入口点的虚拟内存地址。
e_phoff和e_shoff
程序头表偏移量 (e_phoff)
描述程序头表在文件中的偏移量。
节头表偏移量 (e_shoff)
描述节头表在文件中的偏移量。
标志 (e_flags)
描述ELF文件的各种属性,如是否为可重定位文件。
ELF头部大小 (e_ehsize)
描述ELF头部的大小。
e_*entsize和e_*num
程序头表项大小 (e_phentsize)
描述每个程序头表项的大小。
程序头表项数量 (e_phnum)
描述程序头表中有多少个表项。
节头表项大小 (e_shentsize)
描述每个节头表项的大小。
节头表项数量 (e_shnum)
描述节头表中有多少个表项。
字符串表索引 (e_shstrndx)
描述字符串表在节头表中的索引。