Linux下ELF文件解析
字数 3622 2025-08-15 21:30:45
Linux下ELF文件解析教学文档
1. ELF文件概述
ELF (Executable and Linkable Format) 是Linux系统中的标准可执行文件格式,类似于Windows中的PE文件格式。ELF文件不仅用于可执行文件(Executable File),还包括:
- 可重定位目标文件(Relocatable Object File)
- 共享目标文件(Shared Object File)
- 核心转储文件(Core Dump File)
2. ELF文件结构分析
2.1 ELF文件查看工具
使用readelf工具可以查看ELF文件信息:
readelf -h <file> # 查看ELF头
readelf -l <file> # 查看程序头表
readelf -S <file> # 查看区段头表
2.2 ELF文件组成结构
一个典型的ELF文件结构如下:
- 文件头(ELF Header)
- 程序头表(Program Header Table)
- 代码段(.text)
- 数据段(.data)
- bss段(.bss)
- 段表字符串表(.shstrtab)
- 段表(Section Header Table)
- 符号表(.symtab)
- 字符串表(.strtab)
- 重定位表(.rel.text)
- 重定位表(.rel.data)
3. ELF文件头(ELF Header)
ELF文件头记录了ELF文件的基本信息,包括:
- 文件类型(32位/64位)
- 目标CPU平台
- 程序入口点
- 程序头表和段头表的位置信息
3.1 文件头数据结构
typedef struct {
unsigned char e_ident[EI_NIDENT]; // ELF标识(16字节)
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; // ELF头大小(字节)
Elf32_Half e_phentsize; // 程序头表项大小
Elf32_Half e_phnum; // 程序头表项数量
Elf32_Half e_shentsize; // 段头表项大小
Elf32_Half e_shnum; // 段头表项数量
Elf32_Half e_shstrndx; // 段头字符串表索引
} Elf32_Ehdr;
3.2 e_ident字段详解
前16字节的e_ident数组包含ELF文件的标识信息:
- 0-3字节:ELF魔数"\x7fELF"
- 第4字节:文件类别(1=32位,2=64位)
- 第5字节:字节序(1=小端,2=大端)
- 第6字节:ELF版本(通常为1)
- 第7-15字节:填充字节(通常为0)
4. 程序头表(Program Header Table)
程序头表记录了每个Segment的相关信息,包括类型、文件偏移、大小、属性等。程序头表管理ELF文件加载后,ELF文件内可加载段到内存映像的映射关系。
4.1 程序头表数据结构
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;
4.2 段类型(p_type)
| 类型值 | 宏定义 | 描述 |
|---|---|---|
| 0 | PT_NULL | 未使用的程序头表项 |
| 1 | PT_LOAD | 可加载程序段 |
| 2 | PT_DYNAMIC | 动态链接信息 |
| 3 | PT_INTERP | 程序解释器 |
| 4 | PT_NOTE | 辅助信息 |
| 5 | PT_SHLIB | 保留 |
| 6 | PT_PHDR | 头表本身 |
| 7 | PT_TLS | 线程局部存储段 |
4.3 段标志(p_flags)
| 值 | 宏定义 | 描述 |
|---|---|---|
| 1 | PF_X | 可执行 |
| 2 | PF_W | 可写 |
| 4 | PF_R | 可读 |
5. 区段头表(Section Header Table)
区段头表记录了ELF文件的主要数据区段信息。
5.1 区段头表数据结构
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;
5.2 常见段类型(sh_type)
| 类型值 | 宏定义 | 描述 |
|---|---|---|
| 0 | SHT_NULL | 未使用的段头表项 |
| 1 | SHT_PROGBITS | 程序数据 |
| 2 | SHT_SYMTAB | 符号表 |
| 3 | SHT_STRTAB | 字符串表 |
| 4 | SHT_RELA | 带加数的重定位项 |
| 5 | SHT_HASH | 符号哈希表 |
| 6 | SHT_DYNAMIC | 动态链接信息 |
| 7 | SHT_NOTE | 注释 |
| 8 | SHT_NOBITS | 无数据(bss) |
| 9 | SHT_REL | 无加数的重定位项 |
| 11 | SHT_DYNSYM | 动态链接符号表 |
| 14 | SHT_INIT_ARRAY | 构造函数数组 |
| 15 | SHT_FINI_ARRAY | 析构函数数组 |
| 16 | SHT_PREINIT_ARRAY | 预构造函数数组 |
5.3 常见段标志(sh_flags)
| 值 | 描述 |
|---|---|
| 0 | 默认属性 |
| 1 | 段可写(SHF_WRITE) |
| 2 | 需要分配内存(SHF_ALLOC) |
| 4 | 可执行(SHF_EXECINSTR) |
5.4 常见段
.text: 代码段.data: 数据段.rodata: 只读数据段.bss: 未初始化数据段.symtab: 符号表.strtab: 字符串表.shstrtab: 段表字符串表.rel.text: 代码段重定位表.rel.data: 数据段重定位表
6. ELF符号表(Symbol Table)
符号表保存了程序中的符号信息,包括文件名、函数名、全局变量名等,通常保存在.symtab段中。
6.1 符号表数据结构
typedef struct {
Elf32_Word st_name; // 符号名(字符串表索引)
Elf32_Addr st_value; // 符号值
Elf32_Word st_size; // 符号大小
unsigned char st_info; // 符号类型和绑定
unsigned char st_other; // 符号可见性
Elf32_Section st_shndx; // 段索引
} Elf32_Sym;
6.2 符号类型(st_info)
高4位表示绑定类型,低4位表示符号类型:
绑定类型:
- STB_LOCAL (0): 局部符号
- STB_GLOBAL (1): 全局符号
- STB_WEAK (2): 弱符号
符号类型:
- STT_NOTYPE (0): 未指定类型
- STT_OBJECT (1): 数据对象
- STT_FUNC (2): 函数
- STT_SECTION (3): 段
- STT_FILE (4): 文件名
7. ELF重定位表(Relocation Table)
重定位表记录了需要重定位的位置信息,通常保存在.rel开头的段中。
7.1 重定位表数据结构
typedef struct {
Elf32_Addr r_offset; // 重定位地址
Elf32_Word r_info; // 重定位类型和符号索引
} Elf32_Rel;
7.2 重定位类型
r_info的低8位表示重定位类型,高24位表示符号索引。常见的重定位类型包括:
- R_386_32 (1): 绝对地址引用
- R_386_PC32 (2): PC相对地址引用
- R_386_GOT32 (3): GOT表引用
- R_386_PLT32 (4): PLT表引用
8. ELF字符串表(String Table)
字符串表用于存储各种名称字符串,包括:
.strtab: 符号名字符串表.shstrtab: 段名字符串表
字符串表不是表结构,而是一个连续的文件区域,包含多个以null结尾的字符串。
9. ELF文件加载过程
- 读取ELF头,验证文件格式
- 根据程序头表加载各个Segment到内存
- 解析动态链接信息(如果有)
- 执行重定位操作
- 跳转到入口点(e_entry)开始执行
10. 总结
ELF文件是Linux系统中可执行文件、目标文件和共享库的标准格式,理解其结构对于程序分析、调试和逆向工程至关重要。通过分析ELF文件的各个组成部分,可以深入了解程序的加载和执行过程。