ELF文件格式详解

一、ELF文件格式概述

ELF(Executable and Linkable Format)是一种可执行文件和可链接文件格式,被广泛地应用于Unix和类Unix系统中。ELF格式具有以下特点:

1、二进制格式,支持可执行文件、共享目标文件、目标文件等多种类型;

2、通过段(Section)概念对文件进行组织,段包含代码、数据、符号表等信息;

3、支持动态链接,共享目标文件可以在运行时被加载,共享;

4、可通过读取和修改ELF文件中的信息,实现二进制文件的混淆、加密等操作。

二、ELF文件格式组成

一个ELF文件主要包含三个部分:文件头(ELF header)、节区表(Section header table)和节区(Sections)。

1、文件头(ELF Header)

文件头定义了整个ELF文件的组织结构和属性信息,包括标识、目标类型、节区表的位置和大小等。文件头的结构定义如下:

struct Elf32_Ehdr {
    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;
};

2、节区表(Section Header Table)

节区表是一张记录了整个ELF文件中每个节区的信息的表格。节区表一般位于ELF文件的开头末尾,节区表的信息包括节区的名称、偏移地址、大小等。节区表的结构定义如下:

struct Elf32_Shdr {
    Elf32_Word sh_name;
    Elf32_Word sh_type;
    Elf32_Word sh_flags;
    Elf32_Addr sh_addr;
    Elf32_Off sh_offset;
    Elf32_Word sh_size;
    Elf32_Word sh_link;
    Elf32_Word sh_info;
    Elf32_Word sh_addralign;
    Elf32_Word sh_entsize;
};

3、节区(Sections)

每个节区对应一个文件中的逻辑块,例如代码段、数据段、符号表段、字符串表段等等。节区的定义如下:

struct elf_section {
    Elf32_Word sh_name;
    Elf32_Word sh_type;
    Elf32_Word sh_flags;
    Elf32_Addr sh_addr;
    Elf32_Off sh_offset;
    Elf32_Word sh_size;
    Elf32_Word sh_link;
    Elf32_Word sh_info;
    Elf32_Word sh_addralign;
    Elf32_Word sh_entsize;
    void *data;
};

三、ELF文件格式分析

1、ELF文件标识(ELF Identification)

在ELF文件中,前4个字节称为文件的魔数,标识文件的类型。ELF文件标识的结构定义如下:

#define EI_NIDENT 16

struct Elf32_Ehdr {
    unsigned char e_ident[EI_NIDENT];
    //...
};

e_ident数组前四个字节是文件魔数,分别为0x7F、’E’、’L’、’F’。文件是否是64位还是32位,处理器类型等信息,也在e_ident表中。

2、节区表(Section Header Table)

节区表是定义每个节(Section)的一张表,表中包含了每个节的信息,如名称、大小、对齐方式等。节区表的格式由Elf32_Shdr或Elf64_Shdr表示。

ELF文件中,标准的节区表通常包含以下几个节区:

代码段(.text):存放程序的机器代码,只读不可写。

数据段(.data):存放程序中已初始化的全局变量和静态变量,可读可写。

只读数据段(.rodata):存放程序中的只读数据,如字符串常量等,只读不可写。

符号表(.symtab):存放程序中的全局符号信息,符号表中包含符号名、符号类型、符号地址等。

字符串表(.strtab):存放程序中使用的字符串常量的名称。

重定位表(.rel.text):用于对代码段进行重定位操作。

3、程序头表(Program Header(TWo-level))

程序头表由Elf32_Phdr或Elf32_Phdr数组表示,其名称中的“P”代表“Program”,也就是程序头表。在程序执行时,程序头表会被内核解析并用来对整个进程的映像文件进行映像。

struct Elf32_Phdr {
    Elf32_Word p_type;
    Elf32_Off  p_offset;
    Elf32_Addr p_vaddr;
    Elf32_Addr p_paddr;
    Elf32_Word p_filesz;
    Elf32_Word p_memsz;
    Elf32_Word p_flags;
    Elf32_Word p_align;
};

4、重定位(Relocation)

重定位是指将静态编译的程序映射到内存中执行时,因为内存的地址可能与链接时的地址不同,需要对代码中的地址进行调整,以便代码可以在内存中正常运行。这个过程称为重定位(Relocation),在ELF中,重定位相关的信息保存在重定位表(.rel.text)和重定位表(.rel.data)中。

5、链接(Linking)

链接(Linking)是指将多个目标文件和库,最终链接成一个可执行文件或共享目标文件的过程。链接器会将多个目标文件的节合并为一个文件,并进行符号重定位等处理。

四、ELF文件格式示例

1、C语言程序生成ELF文件示例

// demo.c
#include 

void main() {
    printf("Hello World!\n");
}

使用gcc生成可执行程序demo:

gcc -o demo demo.c

使用objdump查看demo的汇编代码:

objdump -d demo

通过objdump生成的结果可以看到,ELF二进制文件包含了很多信息,包括符号表、重定位表、反汇编的代码等信息。

2、动态链接库(shared object)生成ELF文件示例

多个进程间同时使用同一个共享库,可以减少内存使用,应用程序所用的内存被调用库的代码部分所共享,因为在内存中只有一份副本。所以,动态链接库的好处就在于节约了内存。以下是使用gcc来创建动态链接库:

// demo.c
#include 

void foo() {
    printf("Hello World");
}

void bar() {
    printf("Hello Bar");
}

编译动态链接库:

gcc -shared -o libdemo.so demo.c

编译完成后会生成一个名为libdemo.so的动态链接库文件,接下来需要将生成的动态库文件放到OS默认的动态库搜索目录中(例如/usr/lib目录)。

程序可以通过使用动态链接库进行编译,而不需要手动将库打包进可执行文件中:

// main.c
#include 
#include 

int main() {
    void *handle;
    void (*foo)(), (*bar)();

    handle = dlopen("libdemo.so", RTLD_LAZY);
    if (handle == NULL) {
        printf("Failed to open library.\n");
        return 1;
    }

    foo = dlsym(handle, "foo");
    bar = dlsym(handle, "bar");

    foo();
    bar();

    dlclose(handle);
    return 0;
}

编译可执行程序main:

gcc -o main main.c -ldl

动态链接库和可执行程序main都是ELF文件格式。

五、ELF文件格式的应用

在Linux/BSD等类UNIX系统中,ELF文件格式被广泛应用于可执行程序、共享库、目标文件等类型的二进制文件。ELF文件格式将程序代码、数据、符号表、重定位等信息完整地保存在二进制文件中,为程序的开发、调试、优化提供了很好的基础。

同时,ELF文件格式也被用于二进制代码混淆、加密等操作中,通过修改ELF文件中的信息,可以达到有效保护程序机密性的目的。

六、总结

本文对ELF文件格式进行了详细的阐述,介绍了ELF文件格式的组成、特点以及应用。ELF文件格式是Unix和类Unix系统中常用的二进制文件格式,通过ELF格式,程序的开发、调试、优化等方面得到了很好的支持。同时,ELF文件格式也为程序的保护提供了很好的基础。

原创文章,作者:OCIGZ,如若转载,请注明出处:https://www.506064.com/n/362077.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
OCIGZ的头像OCIGZ
上一篇 2025-02-25 18:17
下一篇 2025-02-25 18:17

相关推荐

  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • C语言贪吃蛇详解

    一、数据结构和算法 C语言贪吃蛇主要运用了以下数据结构和算法: 1. 链表 typedef struct body { int x; int y; struct body *nex…

    编程 2025-04-25

发表回复

登录后才能评论