ELF简介
可执行与可链接格式(Executable and Linkable Format,ELF),是Linux操作系统上的默认二进制格式
ELF用于可执行文件、对象文件、共享库及核心转储。64位ELF二进制格式与32位是相似的,主要区别在于某些头部字段和其他数据结构的大小和顺序。
类型
实例
可重定位的对象文件(Relocatable file)
.o;.a;.ko
可执行的对象文件(Executable file)
vi、gdb、及我们用链接器生成的可执行文件、bash shell 程序
可被共享的对象文件(Shared object file)
.so
核心转储文件(Core Dump File)
当进程意外终止时,系统可以将该进程的地址空间的内容及终止时的一些其他信息转储到核心转储文件 core dump
64位ELF二进制文件的格式和内容:
ELF二进制文件实际上包含4种类型的组件:
ELF 头部(executable header,也称为可执行文件头)、
一系列(可选)程序 头、
多个节、
节对应的各个(可选)节头。 ...
ELF节头
ELF二进制文件中的代码和数据在逻辑上被分为连续的非重叠块,称为节(section)。节没有任何预设的结构体,相反,每个节的结构体取决于内容。实际上,节甚至可能没有任何特定的结构体。通常,节只不过是代码或者数据的非结构化blob。每个节由节头描述,节头指定了节的属性,并允许你找到节中字节的位置。二进制文件中所有节的节头都包含在节头表中。
对节进行划分为链接器的使用提供了方便,当然节也可以被其他工具解析(如静态二进制分析工具),这意味着在设置进程和虚拟内存来执行二进制文件的时候,实际上并不需要每个节所包含的数据,有些节所包含的数据在执行的时候是根本不需要的,如符号信息或者重定位信息。
由于节只为链接器提供视图,因此节头表是ELF格式的可选部分,不需要链接的ELF二进制文件不需要有节头表。如果没有节头表,则ELF头部中的e_shoff字段将设置为零。
为了在进程中加载并执行二进制文件,需要对二进制文件中的代码和数据进行不同的组织,为此ELF二进制文件指定了另一种逻辑组织, 称为段(segment),它们在执行的时候使用,与节相对,节在链接的时候使用。
节的内容的逻辑组织只在 ...
ELF头部
每个ELF二进制文件都是从ELF头部开始的,该头部是一系列结构化的字节,这些字节可以告诉你这是一个什么样的ELF二进制文件,以及在文件的什么地方查找其他内容。要找出ELF头部的格式,可以在/usr/include/elf.h或者ELF规范中查找其类型定义(以及其他与ELF相关的类型和常量的定义)。
64位ELF文件头部:
ELF头部在此以C结构体Elf64_Ehdr的形式表示。如果你在/usr/include/elf.h中查找该结构体的定义,你可能会注意到给出的结构体定义包含诸如Elf64_Half和Elf64_word的类型。这些类型只用于uint16_t和uint32_t等整数类型的预定义(typedef)。
e_ident数组
ELF头部(和ELF二进制文件)以被称为e_ident的16字节数组开始。e_ident数组始终以4字节的“幻数”开头,以此标识该文件为ELF二进制文件。幻数由十六进制数字0x7f组成,后跟字母E、L及F的ASCII字符代码。
紧跟在幻数后面,有更多字节提供了有关ELF二进制文件类型规范的详细信息。在elf.h中,这些字节的索引(e_id ...
ELF节
对于各个节,readelf都会显示相关的基本信息,包括节头表里的索引、节的名称和类型。此外,你还可以查看节的虚拟地址、文件偏移及大小。对包含诸如符号表和重定向表的节,还有一列显示每个条目的大小。最后,readelf还显示每个节的相关标志、链接节的索引(如果存在)、其他信息(特定于节类型)及对齐要求。
.init和.fini节
.init节(清单2-5中的索引11)包含可执行代码,==用于执行初始化工作,并且在二进制文件执行其他代码之前运行。==可执行代码会有SHF_EXECINSTR标志,使用readelf查看Flg列,可发现该值为X❷。将控制权转移到二进制文件的main入口点之前,系统会先执行.init节的代码,如果熟悉面向对象编程,你可以将.init节看作构造函数。
.fini节(索引15)类似于.init节,不同之处在于其在主程序运行完后执行,本质上起到一种析构函数的作用。
.text节
.text节包含程序的主要代码,所以它是二进制文件分析或者逆向工作的重点。
.text节的类型为SHT_PROGBITS❸,因为其包含用户定义的代码。同时要注意节的标志,这些标志位 ...
ELF程序头
程序头表提供了二进制文件的段视图,与节头表提供的节视图相反。早前讨论过的ELF二进制文件的节视图仅适用于静态链接。相比之下,下面我们将要讨论的是段视图。在将ELF二进制文件加载到进程并执行的时候,定位相关代码和数据并确定加载到虚拟内存中的内容时,操作系统和动态链接器就会用到段视图。
ELF段包含零个或多个节,实际上就是把多个节捆绑成单个块。段提供的可执行视图,只有ELF二进制文件会用到它们,而非二进制文件(如可重定位对象)则用不到它们。
程序头表使用Elf64_Phdr结构体类型的程序头对段视图进行编码,每个程序头均包含清单2-11所示的字段。
p_type字段
p_type字段标识了段的类型,该字段的重要类型包括PT_LOAD、PT_DYNAMIC及PT_INTERP。
PT_LOAD类型的段会在创建进程时加载到内存中,程序头的剩余部分描述了可加载块的大小和将其加载到的地址。
通常至少有两个PT_LOAD类型的段,一个包含不可写数据节,另一个包含可写数据节。
PT_INTERP类型的段包含了.interp节,该节提供了加载二进制文件的解释器的名称。 ...