一、什么是ELF文件
- ELF:”Executable and Linkable Format”,可执行和可链接文件
- 定义二进制文件、库文件和核心文件(core或a.out)的格式
- 核心文件(core file),也称为核心转存(core dump),是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。这种信息往往用于调试
- ELF文件通常是编译器或链接器的输出,并且是二进制格式
- ELF规范在Linux上也用于内核本身和Linux内核模块
二、ELF文件剖析
1、最基本ELF结构体组成,可扩展
- ELF header
- File data
使用readelf命令,我们可以查看文件的结构
2、结构详细分析
- ELF header
- Magic(魔术字):提供了关于文件的信息,前四个字是 7f(前缀),45(E),4c(L),46(F)
- 必须的:可以确保在链接或执行期间正确的解释数据
- Class:此值确定文件的体系结构,它可以是32位(= 01)或64位(= 02)架构
- 上图中Magic显示02,readelf命令将其翻译为ELF64文件,说明该文件是64位体系结构的ELF文件
- Data:
- 01:LSB(最低有效位),也称为little-endian(小端序)
- 02:MSB(最高有效位),也称为big-endian(大端序)
- 能够保证文件中其余对象正确解释(以字节为单位)
- 在二进制文件中使用hexdump查看LSB时数据在内存中的实际效果
- Magic(魔术字):提供了关于文件的信息,前四个字是 7f(前缀),45(E),4c(L),46(F)
- Version:版本号
- OS/ABI:
- ABI(Application Binary Interface)每个操作系统和其他操作系统相比有差异的实现方法,该值现实对应期望OP
- ABI Version:有需要可以指定
- Type
- 文件的目的
- CORE (value 4)
- DYN (Shared object file), for libraries (value 3)
- EXEC (Executable file), for binaries (value 2)
- REL (Relocatable file), before linked into an executable file (value 1)
- 文件的目的
- Machine
- machine type (AMD64)
使用 hexdump -C -n 64 /bin/ps 可以查看更多header details
- machine type (AMD64)
File data
- Program Headers or Segments (9)
- Segment(段):用于链接器的执行
- ELF中包含零个或多个段,描述了程序在运行时是如何创建“进程/内存”映射的。内核(kernel)进程会将这些段映射到虚拟地址空间(使用mmap系统调用)
- ELF文件使用文件头和基础数据结构形成一个进程
- 段基址、段限长、特权级
- 示例:
- Program Headers or Segments (9)
- GNU_EH_FRAME:这是GNU C编译器(gcc)使用的排序队列。它存储异常处理程序。因此,当出现问题时,它可以使用此区域正确处理它。
- GNU_STACK:该头用于存储堆栈信息(不应该可执行)
- **scanelf(-e) 和 execstack(-q)可以用来查看栈详情**
Section Headers or Sections (28)
- Section(节):用于对数据和指令进行分类
- Section headers:定义了文件中的所有Section,用于链接和重定位
- 对于可执行文件主要有四个Section(可以通过
readelf -S
查看各部分的访问权限):- .text:包含可执行代码,将被打包为具有读取和执行权限的segment,只会加载一次,因为内容不会更改(可以通过
objdump
查看) - .data:初始化的数据,具有读/写访问权限
- .rodata:初始化的数据,仅具有读取访问权限(A)
- .bss:未初始化的数据,具有读/写访问权限(WA)
- .text:包含可执行代码,将被打包为具有读取和执行权限的segment,只会加载一次,因为内容不会更改(可以通过
- Section groups:一些sections能够组合形成一个整体,较新的链接器支持这种功能
Data

ELF segment 和 section 用上图来解释很恰当,其实就是对于elf文件中一部分相同内容的不同描述映射而已,就是上图红框中标出的内容,就好比一个学院的学生,有人喜欢用一班的学生,二班的学生去描述,也有人用女同学,男同学去描述。一个源程序最终是要转成汇编程序最后才能生成一个可执行目标文件,写过汇编的都知道,汇编每一段开头都有不同的声明,表示接下来这一段的内容是什么,如下图,这就是section,也就是说section本身的作用就是来自于汇编中声明,给链接器用的。
<br />那么segment的作用是什么呢? 多个可重定向文件最终要整合成一个可执行的文件的时候,链接器吧目标文件中相同的 section 整合成一个**segment**,在程序运行的时候,方便**加载器**的加载。
3、静态与动态二进制文件
- 静态和动态是指所用的库
- 动态的:二进制文件需要外部组件才能正确运行
- 静态的:静态二进制文件包含所有库,更大但是具有较好的可移植性
- 如何确定正在使用哪些外部库:
$ ldd /bin/ps
或lddtree
二、二进制分析工具
- Radare2
- 套件
- elfutils
- elfkickers
- pax-utils
三、结论
- ELF文件类型非常灵活,并且支持多种CPU类型,计算机体系结构和操作系统。它也是非常可扩展的:每个文件的构造都不同,具体取决于所需的部分。
- 标头构成文件的重要部分,准确描述了ELF文件的内容