欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ELF文件格式解析

程序员文章站 2022-07-07 12:28:16
...

原文链接:https://blog.csdn.net/feglass/article/details/51469511

1. ELF文件简介

首先,你需要知道的是所谓对象文件(Object files)有三个种类:

  1. 可重定位的对象文件(Relocatable file)
    这是由汇编器汇编生成的 .o 文件。后面的链接器(link editor)拿一个或一些 Relocatable object files 作为输入,经链接处理后,生成一个可执行的对象文件 (Executable file) 或者一个可被共享的对象文件(Shared object file)。我们可以使用 ar 工具将众多的 .o Relocatable object files 归档(archive)成 .a 静态库文件。

  2. 可执行的对象文件(Executable file)
    这我们见的多了。文本编辑器vi、调式用的工具gdb、播放mp3歌曲的软件mplayer等等都是Executable object file。你应该已经知道,在我们的 Linux 系统里面,存在两种可执行的东西。除了这里说的 Executable object file,另外一种就是可执行的脚本(如shell脚本)。注意这些脚本不是 Executable object file,它们只是文本文件,但是执行这些脚本所用的解释器就是 Executable object file,比如 bash shell 程序。

  3. 可被共享的对象文件(Shared object file)
    这些就是所谓的动态库文件,也即 .so 文件。如果拿前面的静态库来生成可执行程序,那每个生成的可执行程序中都会有一份库代码的拷贝。如果在磁盘中存储这些可执行程序,那就会占用额外的磁盘空 间;另外如果拿它们放到Linux系统上一起运行,也会浪费掉宝贵的物理内存。如果将静态库换成动态库,那么这些问题都不会出现。动态库在发挥作用的过程 中,必须经过两个步骤:

    • 链接编辑器(link editor)拿它和其他Relocatable object file以及其他shared object file作为输入,经链接处理后,生存另外的 shared object file 或者 executable file。
    • 在运行时,动态链接器(dynamic linker)拿它和一个Executable file以及另外一些 Shared object file 来一起处理,在Linux系统里面创建一个进程映像。

这里我们主要是以Shared Object File(.so)为重点分析对象,因为我们在逆向APK中会遇到的绝大部分都是此类文件。

2. ELF文件格式

首先,ELF文件格式提供了两种视图,分别是链接视图(linker)执行视图(loader)
ELF文件格式解析
链接视图是以节(section)为单位,执行视图是以段(segment)为单位。链接视图就是在链接时用到的视图,而执行视图则是在执行时用到的视图。上图左侧的视角是从链接来看的,右侧的视角是执行来看的。总个文件可以分为四个部分:

  • ELF header: 描述整个文件的组织。
  • Program Header Table: 描述文件中的各种segments,用来告诉系统如何创建进程映像的。
  • sections 或者 segments:segments是从运行(load)的角度来描述elf文件,sections是从链接(link)的角度来描述elf文件,也就是说,在链接阶段,我们可以忽略program header table来处理此文件,在运行阶段可以忽略section header table来处理此程序(所以很多加固手段删除了section header table)。从图中我们也可以看出,segments与sections是包含的关系,一个segment包含若干个section。
  • Section Header Table: 包含了文件各个segction的属性信息,我们都将结合例子来解释。
    ELF文件格式解析

3. ELF Header

ELF Header里面包含了:

  • 程序头部表(Program Header Table),如果存在的话,告诉系统如何创建进程映像(指向segment区)。
  • **节区头部表(Section Header Table)**包含了描述文件节区的信息,比如大小、偏移等(指向section区)。

我们来观察一下ELF Header的结构体:

#define EI_NIDENT 16
typedef struct {
       unsigned char e_ident[EI_NIDENT];
       ELF32_Half e_type;
       ELF32_Half e_machine;
       ELF32_Word e_version;
       ELF32__Addr e_entry;
       ELF32_Off e_phoff;
       ELF32_Off e_shoff;
       ELF32_Word e_flags;
       ELF32_Half e_ehsize;
       ELF32_Half e_phentsize;
       ELF32_Half e_phnum;
       ELF32_Half e_shentsize;
       ELF32_Half e_shnum;
       ELF32_Half e_shstrndx;
}Elf32_Ehdr;

可以通过运行readelf -h 文件名命令,可以看到ELF Header结构的内容
ELF文件格式解析

在ELF Header中我们需要重点关注以下几个字段:

  • e_entry:程序入口地址
    这个sum.o的进入点是0x0(e_entry),这表面Relocatable objects不会有程序进入点。所谓程序进入点是指当程序真正执行起来的时候,其第一条要运行的指令的运行时地址。因为Relocatable objects file只是供再链接而已,所以它不存在进入点。而可执行文件test和动态库.so都存在所谓的进入点,且可执行文件的e_entry指向C库中的_start,而动态库.so中的进入点指向 call_gmon_start。
  • e_ehsize:ELF Header结构大小
  • e_phoff、e_phentsize、e_phnum:描述Program Header Table的偏移、大小、结构。
  • e_shoff、e_shentsize、e_shnum:描述Section Header Table的偏移、大小、结构。
  • e_shstrndx:这一项描述的是字符串表在Section Header Table中的索引,值25表示的是Section Header Table中第25项是字符串表(String Table)。

4. Section Header Table

一个ELF文件中到底有哪些具体的 sections,由包含在这个ELF文件中的 section head table(SHT)决定。在SHT中,针对每一个section,都设置有一个条目(entry),用来描述对应的这个section,其内容主要包括该 section 的名称、类型、大小以及在整个ELF文件中的字节偏移位置等等。我们也可以在TISCv1.2规范中找到SHT表中条目的C结构定义:
ELF文件格式解析

5. Program Header Table

程序头部(Program Header)描述与程序执行直接相关的目标文件结构信息。用来在文件中定位各个段的映像。同时包含其他一些用来为程序创建映像所必须的信息。
可执行文件或者共享目标文件的程序头部是一个结构数组,每个结构描述了一个段或者系统准备程序执行所必须的其他信息。目标文件的“段”包含一个或者多个“节区”,也就是“段内容(Segment Contents)”。程序头部仅对可执行文件和共享目标文件有意义。

程序头部的数据结构如下:

typedef struct {  
    Elf32_Word p_type;           //此数组元素描述的段的类型,或者如何解释此数组元素的信息。 
    Elf32_Off  p_offset;           //此成员给出从文件头到该段第一个字节的偏移
    Elf32_Addr p_vaddr;         //此成员给出段的第一个字节将被放到内存中的虚拟地址
    Elf32_Addr p_paddr;        //此成员仅用于与物理地址相关的系统中。System V忽略所有应用程序的物理地址信息。
    Elf32_Word p_filesz;         //此成员给出段在文件映像中所占的字节数。可以为0。
    Elf32_Word p_memsz;     //此成员给出段在内存映像中占用的字节数。可以为0。
    Elf32_Word p_flags;         //此成员给出与段相关的标志。
    Elf32_Word p_align;        //此成员给出段在文件中和内存中如何对齐。
} Elf32_phdr;
相关标签: linux elf文件