ELF文件格式

1 ELF定义

  ELF(Executable and Linkable Format,可执行与可链接格式)是目前UNIX 和类 UNIX 操作系统的标准二进制格式文件。linux系统中的可执行文件(exe)、共享库(.so)、目标文件(.o)、coredump文件都是ELF格式,只是文件类型不同

  ps: 静态共享文件(.a)是目标文件(.o)的集合

2 ELF结构

       ELF文件一般会包括如下几个内容:ELF头、Program头、Section头和Section

    

 

 2.1 ELF头

       ELF文件的第一个部分,/usr/include/elf.h中有定义ELF文件头的格式

     

  可以通过readelf –h 查看elf头,如下图:

  

  ps: TYPE类型对应关系如下

         ET_NONE       --    无类型

    ET_REL          --    可重定位文件(.o)

    ET_EXEC        --   可执行文件

    ET_DYN         --    共享库

    ET_CORE       --    核心转储文件

 2.2 Program头

       一个elf文件会有多个program头,每个program头描述一个段(segment)的信息。加载器通过读取程序头表,将段加载到内存中,从而正确的执行可执行文件或共享库。

       这里的段(segment)不是代码段,数据段,它表示一些section的集合,这个section具有相同的读写/执行属性, 可以被加载到内存中的一个整体操作单元。段是程序执行的必要组成部分,因此可执行文件中,program头是必须的。

       readelf –l命令可以查看程序头,看到每个段包含哪些section 

       

 

 2.3 Section和Section头 

  ELF 二进制文件中的代码和数据在逻辑上被分为连续的非重叠块,称为节(section)。而节头(Section Header)描述了文件中的各个节与链接和重定位相关的信息、调试信息和其他数据。每个ELF文件可以有多个节,每个节在节头表中都有一个对应的条目。节头表包含了所有节头的列表。

  readelf –S 查询section信息 

       

  常见的section如下:

   .init 节包含可执行代码,用于执行初始化工作,并且在二进制文件执行其他代码之前运行。可执行代码会有 SHF_EXECINSTR 标志, 使用 readelf 查看 Flg 列,可发现该值为 X。将控制权转移到二进制文件的 main 入口点之前,系统会先执行.init 节的代码,如果熟悉面向对象编程,你可以 将.init 节看作构造函数。.fini 节类似于.init 节,不同之处在于其在主程序运行完后执行,本质上起到一种析构函数的作用。

​   .text 节包含程序的主要代码,所以它是二进制文件分析或者逆向工作的重点。.text 节的类型为 SHT_PROGBITS,因为其包含用户定义的代码。同时要注意节的标志,这些标志位指定了该节为可执行的节, 但不可写入。一般来说,可执行的节是不可写的,反之,可写的节一般是不可执行的,因为既可写又可执行的节会让攻击者利用漏洞直接覆盖代码来修改程序。

​   .rodata 节代表“只读数据”,用于存储常量,因此.rodata 节是不可写的。 初始化变量的默认值存储在.data 节中,因为变量的值可能会在运行时修改,所以该节被标记为可写。

​   .data节存在于data段中,保存了初始化的全局变量等数据。由于其保存了程序的变量数据,因此节类型被标记为SHT_PROGBITS。

​   .bss 节为未初始化的变量保留空间,最初.bss 节的名称 代表着“以符号开头的块”,是为(符号)变量保留内存块的意思。 与类型为 SHT_PROGBITS 的.rodata 节和.data 节不同,.bss 节的类型为 SHT_NOBITS,这是因为.bss 节不会像二进制文件一样占用磁盘上的字节,它只当二进制文件建立执行环境时为未初始化的变量分配适当大小的内存块。一般来 说,.bss 节中的变量被初始化为零,并且该节被标记为可写。

​   .plt是过程链接表(Procedure Linkage Table,PLT),.plt节中包含了动态链接器调用从共享库导入的函数所必需的相关代码。由于其存在于text段中,同样保存了代码,因此节类型为SHT_PROGBITS。

​   .got节保存了全局偏移表。.got节和.plt节一起提供了对导入的共享库函数的访问入口,由动态链接器在运行时进行修改。如果攻击者获得了堆或者.bss漏洞的一个指针大小的写原语,就可以对该节任意进行修改。.got.plt节跟程序执行有关,因此节类型被标记为SHT_PROGBITS。

  ​ .dynsym节保存了从共享库导入的动态符号信息,该节保存在text段中,节类型被标记为SHT_PROGBITS。

​   .dynstr节保存了动态符号字符串表,表中存放了一系列字符串,这些字符串代表了符号的名称,以空字符作为终止符。

​   .rel.*节,即重定位节,保存了重定位相关的信息,这些信息描述;了在链接或者运行时,对ELF目标文件的某部分内容或者进程镜像进行补充或者修改。重定位节保存了重定位相关的数据,因此节类型被标记为SHT_REL。

​   .hash节有时也称为.gnu.hahs,保存了一个用于查找符号的散列表。

​   .symtab节保存了ElfN_Sym类型的符号信息,因此节类型被标记为SHT_SYMTAB。

​   .strtab节保存的是符号字符串表,表中的内容会被.symtab的ElfN_Sym结构中的st_name条目引用。由于其保存了字符串表,因此节类型被标记为SHT_STRTAB。

​   .shstrtab节保存节头字符串表,该表是一个以空字符终止的字符串的集合,字符串保存了每个节的节名,如.text、.data等。有一个名为e_shsrndx的ELF文件头条目会指向.shstrtab节,e_shstrndx中保存了.shstrtab的偏移量。由于其保存了字符串表,因此节类型被标记为SHT_STRTAB。

​   .ctors(构造器)和.dtors(析构器)这两个节保存了指向析构函数和析构函数的指针,构造函数是在main函数执行之前需要执行的代码,析构函数是在main函数之后需要执行的代码

参考文档:

https://zhuanlan.zhihu.com/p/706472463

https://blog.csdn.net/u014587123/article/details/115276998

  

posted @   ho966  阅读(142)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示