本文主要是介绍二进制分析 ELF格式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
简介: ELF 用于可执行文件,对象文件,共享库及核心转储,是UN IX系统实验室作为二进制接口而开发和发布
组成部分 | |
ELF 头部 | 该头部是一系列结构化的字节,描述是什么样的二进制文件及在文件的什么地方找到其他内容 可以在 /usr/include/elf.h 或规范中找到其它内型的定义 |
程序头 | 描述的是一个段在文件中的位置,大小以及它被放进内存后所在的位置和大小 |
节 | 二进制文件中的代码和数据在逻辑上被分为连续的非重叠块 |
节头 | 指定节的属性,并允许找到节中字节的位置 |
ELF 头部结构 | |
unsigned char e_ident[16] | /* Magic number and other info */ [0~3]: 幻数,0x7f 说明在处理一个ELF 文件 [4]: EI_CLASS,系统类型,表示用32位还是64位 [5]: EI_DATA,字节顺序(大端还是小段) [6]: EI_VERSION,使用ELF 规范版本 [7]: EI_OSABI ,二进制接口,非零表示文件中会使用一些ABI 或OS 的具体扩展名 [8]: EI_ABIVERSION,表示EI_OSABI 字节指定的ABI版本 [9~15]: EI_PAD,保留字节,供将来使用 |
uint16_t e_type | /* Object file type */ 指定文件类型, ET_REL: 可重定位对象文件 ET_EXEC: 可执行的二进制文件 ET_DYN: 动态库 |
uint16_t e_machine | /* Architecture */ 运行架构体系, EM_X86_64: 64位x86 EM_386: 32位x86 EM_ARM: ARM二进制文件 |
uint32_t e_versioin | /* Object file version */ 使用的ELF 规范版本 |
uint64_t e_entry | /* Entry point virtual address */ 二进制文件的入口点,应该执行的虚拟地址 |
uint64_t phoff | /* Program header table file offset */ 程序表距离开始的偏移量 |
uint64_t e_shoff | /* Section header table file offset */ 节头表距离开始的偏移量 |
uint32_t e_flags | /* Processor-specific flags */ 处理器标志,ARM,X86,... |
uint16_t e_ehsize | /* ELF header size in bytes */ ELF 头部大小 |
uint16_t e_phentsize | /* Program header table entry size */ 程序头表大小 |
uint16_t e_phum | /* Program header table entry count */ 程序头表程序头数量 |
uint16_t e_shentsize | /* Section header table entry size */ 节头表大小 |
uint16_t e_shum | /* Section header table entry count */ 节头表节的数量 |
uint16_t e_eshstrndx | /* Section header string table index */ 表示字符串表在节头表中的索引 |
程序头结构 Elf64_Phdr | |
uint32_Word p_type | /* Segment type */ 标识段类型: PT_LOAD: 在创建进程时加载到内存中 PT_DYNAMIC:包含.dynamic 节,告诉解析器如果解析二进制文件用于执行 PT_INTERT:包含了.interp节该节提供了加载二进制文件的解析器的名称 ... |
uint32_Word p_flags; | /* Segment flags */ 指定段子啊运行时的访问权限 PF_X:该段可执行 PF_W: 该段可写 PF_R:可读 |
uint64_Off p_offset; | /* Segment file offset */ 段起始文件便宜量 |
uint64_Addr p_vaddr; | /* Segment virtual address */ 加载的虚拟地址 |
uint64_Addr p_paddr; | /* Segment physical address */ 加载的物理地址,在某些系统上,可以指定段在物理内存的那个地址上执行 |
uint64_Xword p_filesz; | /* Segment size in file */ 段大小 |
uint64_Xword p_memsz; | /* Segment size in memory */ 内存大小 |
uint64_Xword p_align; | /* Segment alignment */ 指定段所需要的内存对齐方式 |
节头Elf64_Shdr | |
uint32_Word sh_name; | /* Section name (string tbl index) */ 名字索引,如果为0,表示该节没有索引 init,fini,text,..... |
uint32_Word sh_type; | /* Section type */ 类型: SHT_PROGBITS: 包含了程序数据 SHT_SYSMATA: 静态符号表 SHT_DYNSYM: 动态链接器符合表 SHT_STRTAB: 字符串标 SHT_REL: SHT_REAL .... |
uint64_Xword sh_flags; | /* Section flags */ 节标志: SHF_WRITE: 指示该节在运行时可写 SHF_ALLOC: 指示执行二进制文件时讲节的内容加载到虚拟内存中 |
uint64_Addr sh_addr; | /* Section virtual addr at execution */ 该节的虚拟地址 |
uint64_Off sh_offset; | /* Section file offset */ 该节的文件便宜量 |
uint64_Xword sh_size; | /* Section size in bytes */ 节的大小 |
uint64_Word sh_link; | /* Link to another section */ 链接到下一个节 |
uint64_Word sh_info; | /* Additional section information */ 存放关于节的额外信息,依赖于节的类型 |
uint64_Xword sh_addralign; | /* Section alignment */ 在内存中的对齐方式 |
uint64_Xword sh_entsize; | /* Entry size if section holds table */ 某些节包含固定大小的条目,该字段指定每个条目的长度字节数,如果为0则并不包含固定长度条目的表格 |
节 | ||
名称 | 类型 | 说明 |
.interp | PROGBITS | interp字段的值是一个字符串指针,指向文件头中的interp_name字段,用于指定解释器或加载器的名称 例如,如果ELF文件是为C++程序编译的,那么interp_name字段可能包含“ld-linux-x86-64.so.2”的字符串,表示GNU linker(ld)程序。 |
.note.ABI-tag | NOTE | 用于存储文件的应用二进制接口(ABI)信息。ABI是一个程序的接口定义,用于描述程序的可执行代码和库之间的交互方式。 包含了文件的ABI版本号、ABI类型(例如,32位或64位)以及其他相关信息 |
.note.gnu.build-id | NOTE | 用于存储文件的唯一标识符(build ID)。build ID是一个字符串,用于标识文件的构建过程和源代码。 用于标识文件的构建过程和源代码。它用于帮助诊断和调试问题,因为它可以帮助跟踪文件的来源和构建过程。 |
.gnu.hash | GNU_HASH | 用于存储文件的哈希值。哈希值是一个字符串,用于标识文件的内容和结构。 通常由文件的构建过程生成。这个字符串通常包含文件的哈希值,用于帮助诊断和调试问题,因为它可以帮助跟踪文件的内容和结构。 |
.dynsym | DYNSYM | 用于存储动态符号表(dynsym)信息。动态符号表是一个数据结构,用于描述程序中的动态符号(例如,库和其他程序中的函数和变量)。 用于帮助程序在运行时查找和链接动态库中的符号。 |
.dynstr | STRTAB | 用于存储动态字符串表(dynstr)信息。动态字符串表是一个数据结构,用于存储程序中的动态字符串(例如,库和其他程序中的函数和变量名称)。 |
.gun.version | VERSYM | 用于存储文件的GNU版本信息。GNU版本信息是一个字符串,用于标识文件的GNU工具链版本。 |
.gun.version_r | VERNEED | 用于存储文件的GNU运行时版本信息。GNU运行时版本信息是一个字符串,用于标识文件的GNU运行时库版本。 |
.rela.dyn | RELA | 记录所有变量的动态链接器重定位信息与rela.plt 一起使用 |
.rela.plt | RELA | 过程的动态链接重定位表 |
.init | PROGBITS | 在执行其他代码之前的初始化(类似构造函数) |
.plt | PROGBITS | 过程链接表(用于延迟绑定:在运行中需要的时候执行) |
.plt.got | PROGBITS | 全局偏移量表(用于延迟绑定) |
.text | PROGBITS | 主要代码,包含用户代码,注意节的标志,一般来说可执行就不可写,可写就不可执行,因为可执行又可写就会被攻击者利用,直接覆盖代码来修改程序 |
.fini | PROGBITS | 主程序运行完成后执行的代码(类似析造函数) |
.rodata | PROGBITS | 只读数据,用于存储常量 |
.en_frame_hdr | PROGBITS | 用于存储程序的执行框架头部信息。执行框架头部是一个数据结构,用于描述程序的执行框架和运行时状态。 |
.en_frame | PROGBITS | 用于存储程序的执行框架信息。执行框架是一个数据结构,用于描述程序的执行框架和运行时状态。 |
.init_array | INIT_ARRAY | 包含一个指向构造函数的指针数组,在main 之前会被依次调用,与init 不同的时它是数据节(指针可被修改,使其方便插入钩子的位置) |
.fini_array | FINT_ARRAY | 包含指向析构函数数组指针(指针可被修改,使其方便插入钩子的位置) |
.jcr | PROGBITS | |
.dynamic | DYNAMIC | 用于存储文件的动态链接信息。动态链接信息是一个数据结构,用于描述程序中的动态链接(例如,库和其他程序中的函数和变量)。 |
.got | PROGBITS | 用于存储文件的全局偏移表(got)信息 |
.got.plt | PROGBITS | 用于存储文件的程序链接表(plt)信息。程序链接表是一个数据结构,用于描述程序中的程序链接(例如,库和其他程序中的函数和变量)。 |
.data | PROGBITS | 初始化变量的默认值 |
.bss | PROGBITS | 为未初始化的变量保留空间 |
.comment | PROGBITS | 用于存储文件的注释信息。注释信息是一个字符串,用于描述文件的注释信息。 |
.shstrtab | STRTAB | 以NULL 结尾的字符串数组,包含所有的节的名称,通过节名称进行索引 |
.symtab | SYMTAB | 包含一个符合表,该表是一个ELF65_Sym 结构体数组,每个条目都将符合名与二进制文件中的代码和数据相关联,包含符号名的实际字符串保存到strtab 中 |
.strtab | STRTAB | 符号名的实际字符串 |
这篇关于二进制分析 ELF格式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!