ELF文件格式详解

摘要

本文描述了Linux系统的ELF文件格式。

ELF文件格式简介

ELF(Executable and Linkable Format)是一种常用的二进制文件格式,用于存储可执行文件、共享库和核心转储文件。它是由Linux操作系统所采用和支持的标准格式。

ELF文件共有四种形式:

1. 可执行文件(Executable file):是一种包含可直接执行程序的ELF文件,可以直接在操作系统上运行。

2. 共享目标文件(Shared object file):是一种包含函数和变量等可被多个可执行程序同时调用的ELF文件,通常被称为动态链接库或共享库(Shared Library)。多个程序可以共享同一份共享库,这样可以减少系统资源的浪费并提高程序的运行效率。

3. 目标文件(Object file):是一种包含已编译的代码和数据但还未被链接成可执行文件或共享库的ELF文件。目标文件通常会被多次编译和链接,直到最终生成可执行文件或共享库。

4. 崩溃转储文件(Core file):Core文件是在Linux和其他UNIX系统中生成的一种特殊文件,它记录了进程在崩溃或异常终止时的内部状态,包括进程的内存映像、寄存器状态、堆栈跟踪信息以及其他调试信息。Core文件通常用于调试崩溃或异常终止的程序。

ELF目标文件结构图

下图左侧是ELF的目标文件结构,右侧是ELF可执行文件结构。

ELF文件结构图

ELF文件结构定义

ELF文件结构的定义在头文件elf.h中,其典型路径为:

/usr/include/elf.h

ELF文件类型

ELF文件的四种类型定义如下:

#define ET_NONE  0      /* No file type */
#define ET_REL   1      /* Relocatable file type */
#define ET_EXEC  2      /* Executable file type */
#define ET_DYN   3      /* Shared object file type */
#define ET_CORE  4      /* Core file type */

ELF头

#define EI_NIDENT (16)
 
typedef struct elf32_hdr{
    unsigned char e_ident[EI_NIDENT];     /* 魔数和相关信息 */
    Elf32_Half    e_type;                 /* ELF文件类型,参考上节的定义 */
    Elf32_Half    e_machine;              /* 硬件体系,例如:Intel 80386 */
    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;

e_ident字段定义如下:

e_ident Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2’s complement, little end
Version: 1(current)
OS/ABI: UNIX - System V
ABI Version: 0

程序头表

程序头表属于ELF的可选内容,通常位于类型为ET_EXEC的可执行文件中。

类型为ETL_REL的可重定位文件(扩展名为.o)是没有成不头表的。

程序头表项定义:

typedef struct elf32_phdr{
  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;

程序头表示例:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
-----------------------------------------------------------------------------
  EXIDX          0x000884 0x00008884 0x00008884 0x00008 0x00008 R   0x4
  PHDR           0x000034 0x00008034 0x00008034 0x00140 0x00140 R E 0x4
  INTERP         0x000174 0x00008174 0x00008174 0x00013 0x00013 R   0x1
  LOAD           0x000000 0x00008000 0x00008000 0x00890 0x00890 R E 0x8000
  LOAD           0x000f04 0x00010f04 0x00010f04 0x0014c 0x00154 RW  0x8000
  DYNAMIC        0x000f10 0x00010f10 0x00010f10 0x000f0 0x000f0 RW  0x4
  NOTE           0x000188 0x00008188 0x00008188 0x00020 0x00020 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
  GNU_RELRO      0x000f04 0x00010f04 0x00010f04 0x000fc 0x000fc R   0x1

节头表

节头表通常位于ELF文件的尾部,其文件内偏移由ELF头结构的e_shoff字段指示。

typedef struct {
    Elf64_Word    sh_name; /* 节名称,是节区头字符串表节区中的索引。*/
    Elf64_Word    sh_type;
    Elf64_Xword   sh_flags; /* 内存访问属性:可度,可写,可执行,是否需要分配内存等。*/
    Elf64_Addr    sh_addr;
    Elf64_Off     sh_offset;
    Elf64_Xword   sh_size;
    Elf64_Word    sh_link;
    Elf64_Word    sh_info;
    Elf64_Xword   sh_addralign;
    Elf64_Xword   sh_entsize;
} Elf64_Shdr;

节内容

系统预定义的节名称及含义如下:

sh_name sh_type 说明

.text

SHT_PROGBITS

代码段,包含程序的可执行指令

.data

SHT_PROGBITS

已初始化数据,将出现在程序的内存映像中

.bss

SHT_NOBITS

未初始化数据,因为只有符号所以

.rodata

SHT_PROGBITS

只读数据

.comment

SHT_PROGBITS

版本控制信息

.dynsym

SHT_DYNSYM

动态链接符号表

.shstrtab

SHT_STRTAB

节头字符串表

.strtab

SHT_STRTAB

字符串表

.symtab

SHT_SYMTAB

符号表

ELF文件分析

objdump是一个用于查看ELF文件中二进制代码、目标文件、共享库、静态库等信息的工具,是GNU Binutils套件中的一个组件。

反汇编应用程序

objdump -d  hello.o  

显示文件头信息 

objdump -f hello.o

显示指定节名的信息

objdump -s -j .comment hello.o

参考资料

ELF文件格式解析

ELF文件格式的详解

ELF 格式详解

ELF与PE对比

ELF和PE都是COFF(Common File Format)格式的变种,两者对比如下:

  1. ELF文件开篇就是ELF头,无DOS头这类历史包袱;PE文件为了兼容DOS程序,开篇就是DOS头和DOS存根程序,由DOS头的e_lfanew字段指示PE头在文件内的偏移。
  2. ELF文件的ELF头相当于PE文件的映像文件头。
  3. ELF文件的程序头相当于PE文件的PE可选头。
  4. ELF文件中节头表位于节内容之后,偏移由ELF头的e_shoff字段指定,节头数量由e_shnum字段指定;PE的节头表位于节内容之前,紧跟在PE可选头之后,以全零的节头表项作为结束标志。

ELF文件格式比PE文件格式简单。

总结

ELF文件格式是现代操作系统和编程语言中最常见的可执行文件格式之一。了解ELF文件格式很重要,因为:

1. 在开发中需要知道如何生成ELF文件格式的输出。编译器和链接器通常使用ELF文件格式来生成可执行文件或共享库。了解ELF文件格式的细节可以帮助程序员了解编译器和链接器如何工作,并且可以通过对编译器和链接器参数的调整来更好地优化程序。

2. 在调试和优化程序时,了解ELF文件格式可以帮助我们识别和理解程序的符号表、调试信息、代码段、数据段等。这些信息可以帮助我们更好地理解程序的执行,从而更好地调试和修复程序。

3. 在开发反汇编或二进制分析工具时,了解ELF文件格式可以帮助我们识别可执行文件或共享库的结构和组成,从而更好地理解这些文件的内容,以及它们是如何工作的。

4. 在安全研究领域,了解ELF文件格式可以帮助我们分析和理解各种漏洞利用技术,例如栈溢出、格式字符串漏洞、ROP链等。同时,也可以帮助我们识别和分析各种恶意软件和代码,从而更好地保护我们的系统。

总之,对ELF文件格式的了解可以帮助我们在程序开发、调试、分析和安全等方面变得更加高效和熟练。

猜你喜欢

转载自blog.csdn.net/bigwave2000/article/details/132645847
今日推荐