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文件结构如下:

  1. 文件头(ELF Header)
  2. 程序头表(Program Header Table)
  3. 代码段(.text)
  4. 数据段(.data)
  5. bss段(.bss)
  6. 段表字符串表(.shstrtab)
  7. 段表(Section Header Table)
  8. 符号表(.symtab)
  9. 字符串表(.strtab)
  10. 重定位表(.rel.text)
  11. 重定位表(.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文件加载过程

  1. 读取ELF头,验证文件格式
  2. 根据程序头表加载各个Segment到内存
  3. 解析动态链接信息(如果有)
  4. 执行重定位操作
  5. 跳转到入口点(e_entry)开始执行

10. 总结

ELF文件是Linux系统中可执行文件、目标文件和共享库的标准格式,理解其结构对于程序分析、调试和逆向工程至关重要。通过分析ELF文件的各个组成部分,可以深入了解程序的加载和执行过程。

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文件信息: 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 文件头数据结构 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 程序头表数据结构 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 区段头表数据结构 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 符号表数据结构 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 重定位表数据结构 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文件的各个组成部分,可以深入了解程序的加载和执行过程。