ELF文件格式

举报
御麟 发表于 2023/04/25 22:13:14 2023/04/25
【摘要】 ELF文件格式

 Executable and Linkable Format是Linux操作系统上默认的二进制格式

一个可以执行的文件就是存储了一些数据和代码,我们要明白ELF文件有哪些部分,每一部分记录了文件的什么信息

                                我偷偷把星星散布于自己个人的天空,在那里创造我的无限                                                                                                           ——费尔南多·佩索阿

目录

二进制分析


ELF文件包括了4种类型的组件

ELF头部

e_ident数组

幻数

EI_CLASS

EI_DATA

EI_VERSION

EI_OSABI和EI_ABIVERSION

EI_PAD

使用readelf命令查看e_ident

e_type字段

e_machine字段

e_version字段

e_entry字段

e_phoff和e_shoff字段

e_flags字段

e_ehsize字段

e_*entsize和e_*num字段

e_shstrndx字段

节头

sh_name字段

sh_type字段

sh_flags字段

sh_addr,sh_offset及sh_size字段

sh_link字段

sh_info字段

sh_addralign字段

显示节

.init节

.fini节

.text节

.bss,.data及.rodata节

延迟绑定和.plt,.got和.got.plt节

延迟绑定和.plt

使用PLT动态解析库函数

其他节

.rel.和.rela.*节

.dynamic节

.init_array和.fini_array节

.shstrtab、.symtab、.strtab、.dynsym及.dynstr节

程序头

p_type字段

p_flags字段

p_offset、p_vaddr、p_paddr、p_filesz和p_memsz字段

p_align字段



二进制分析

什么是漏洞

漏洞的英文是leak

编辑

leak在英语语境中是一种气体,液体或者信息的泄露

我们的程序就像水流一样向下运行,用条件判断进行分流 

在这个运行过程中一些设计问题会让攻击者有可乘之机,这就是漏洞

通过漏铜我们可以劫持进程,泄露信息

我们运行的程序是编译过后的机器语言程序,不是高级语言直接运行,所有这个运行过程的漏洞要从二进制层面来发掘,ELF文件格式就是必修的二进制知识

本文就来介绍ELF文件的知识

编辑


ELF文件包括了4种类型的组件

  • ELF头部
  • 程序头
  • 节头

每一块都存储了文件的一部分信息

ELF头部

每个ELF二进制文件都是从ELF头部开始的,该头部是一系列结构化的字节

本质是什么,就是这个文件的头部存储了一些有用的数据,可理解为一个数据结构,就是一个结构体


下使用高级语言的定义

#define EI_NIDENT (16)
 
typedef struct
{
  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
  Elf32_Half    e_type;                 /* Object file type */
  Elf32_Half    e_machine;              /* Architecture */
  Elf32_Word    e_version;              /* Object file version */
  Elf32_Addr    e_entry;                /* Entry point virtual address */
  Elf32_Off     e_phoff;                /* Program header table file offset */
  Elf32_Off     e_shoff;                /* Section header table file offset */
  Elf32_Word    e_flags;                /* Processor-specific flags */
  Elf32_Half    e_ehsize;               /* ELF header size in bytes */
  Elf32_Half    e_phentsize;            /* Program header table entry size */
  Elf32_Half    e_phnum;                /* Program header table entry count */
  Elf32_Half    e_shentsize;            /* Section header table entry size */
  Elf32_Half    e_shnum;                /* Section header table entry count */
  Elf32_Half    e_shstrndx;             /* Section header string table index */
} Elf32_Ehdr;

我们来一部分一部分进行一下解读


e_ident数组

 010Editor

这里先介绍一款二进制编辑工具的使用

编辑

这是一款强大的二进制编辑工具和十六进制编辑工具

我们存储的文件都是二进制的形式,这款工具可以查看二进制,默认是十六进制表示

可以直接修改这些二进制

编辑

看上面的定义是一个16字节的数组

幻数

第一部分是一个4字节的幻数,由0x7F和ELF的ASCLL码组成

我们看一下010edior的开头

编辑

左侧是16进制表示的二进制数据,右侧是左侧数据对应的ASCLL表示,'.'表示不可见字符

紧跟在幻数后面的字节提供了有关ELF二进制文件类型规范,就是e_ident的4~15索引

下面介绍这些部分,参考上图,或者自己找一个ELF文件用010editor查看

EI_CLASS

表示ELF规范中二进制文件的类,这个字节表示用的是32位还是64位体系结构
32位是1,64位是2

EI_DATA

指示二进制文件中的字节序

等于1是小端法,等于2是大端法

EI_VERSION

指示的是ELF版本规范,当前唯一有效的有效值是1

EI_OSABI和EI_ABIVERSION

表示的是应用程序的二进制接口

EI_PAD

这个部分包含很多字节,是 e_ident的9~15字节

当前设置都是0,保留供将来用

使用readelf命令查看e_ident

除了010editor,我们还可以在Linux中使用readelf命令查看文件的e_ident

命令与显示如图

编辑

Magic所显示的就是 e_ident

而且下面对于e_ident表示的信息进行了解读

还有显示了接下来的字段的内容解读


e_type字段

这里经常遇到的值是ET_REL(可重定位的对象文件),ET_EXEC(可执行的二进制文件),ET_DNY(动态库)


e_machine字段

表示二进制文件计划在什么体系结构上运行

EM_X86_64   EM_386   EM_ARM


e_version字段

作用与 e_ident数组中的EI_VERSION相同

唯一可能的值是EV_CURRENT,指定版本规范是1


e_entry字段

表示二进制文件的入口点

开始执行的虚拟地址


e_phoff和e_shoff字段

程序头和节头不必位于ELF文件中的任意特定偏移

e_phoff和e_shoff字段指定了程序头表和节头表距离开始的偏移量


e_flags字段

保存了二进制文件在特定处理器的标志

对于x86二进制文件,通常设置为0,无须过多关注


e_ehsize字段

指定了ELF头部的大小

64位始终为64字节,32位始终为52字节


e_*entsize和e_*num字段

每个程序头或者表中各个节头的大小


e_shstrndx字段

包含一个名为.shstrtab的,与特殊字符串表结相关的头索引


节头

ELF二进制文件中的代码和数据在逻辑上被分为连续的非重叠块,称为节

没有预设的结构体,每个节的结构体取决于内容

编辑

sh_name字段

如果这个子段被设置,字符串表中包含索引


sh_type字段

每个节的类型


sh_flags字段

SHF_WRITE 该节在运行时可写

SHF_ALLOC 指示在执行二进制文件时将节的内容加载到虚拟内存

SHF_EXECINSTR 指示该节包含可执行指令


sh_addr,sh_offset及sh_size字段

分别描述该节的虚拟地址,文件偏移和大小


sh_link字段

有时链接器需要了解节与节之间的关系,例如与SHT_SYMAB,SHT_DYNSYM或者SHT_DYNAMIC类型的节有关联的字符串表节,其中包含相关符号的名称


sh_info字段

存放关于节的额外信息,这些额外信息依赖与解类型


sh_addralign字段

包含固定大小的条目


显示节

使用readelf命令显示节

编辑

显示了节的虚拟地址,文件偏移和大小

.init节

包含可执行代码,用于执行初始化工作,并且在二进制文件执行其他代码之前运行,类似面向对象编程的构造函数

.fini节

在主程序运行完后执行,类似析构函数

.text节

包含程序的主要代码,是逆向分析的重点

包含了很多执行初始化和终止任务的标准函数,如_start,register_tm_clones,frame_dummy

.bss,.data及.rodata节

.rodata 保存只读数据

.data 存储可写的数据

.bss 初始化为0,并且标记该节为可写

延迟绑定和.plt,.got和.got.plt节

加载二进制文件的时候很多重定位一般都不会立即完成,而是延迟到对未解析位置进行首次引用之前,这就是延迟绑定

编辑

延迟绑定和.plt

延迟绑定保证了动态链接器不会在重定位上浪费时间,只在运行有需要的时候执行

延迟绑定用.plt节和.got节

通常有一个.got.plt的GOT

.plt是包含可执行代码的代码节

.got.plt是数据节

查看plt

编辑

PLT的格式如下

首先有一个默认存根,然后是一系列函数存根,每个库函数有一个存根

编辑

然后是一系列函数存根

编辑

压入栈的值依次递增,观察上图的push

使用PLT动态解析库函数

假设调用puts函数

已知该函数是libc库的一部分

可以直接调用相应的PLT存根puts@plt,不是直接调用该函数

push指令把一个整数压入栈,该整数是PLT存根的标识符

下一条转到所有PLT函数的存根之间共享的通用默认存根

默认存根会push另一个标识符,以表示可执行文件自身

然后间接地,通过GOT跳转到动态链接器 

其他节

.rel.和.rela.*节

有几个名为.rela.*的节

类型为SHT_RELA

包含链接器用于执行重定位的信息

每个SHT_RELA类型是一个重定位条目

编辑

.dynamic节

.dynamic节将充当操作系统和动态链接器的“路线图”

编辑

包含了一个Elf64_Dyn的结构体数组

也称为标签,有各种类型,每个标签有个关联值

DT_NEEDED的标签会通知通知动态链接器关于可执行文件的依赖问题


.init_array和.fini_array节

.init_array包含一个指向构造函数的指针数组

.fini_array包含一个指向析构函数的指针

编辑


.shstrtab、.symtab、.strtab、.dynsym及.dynstr节

.shstrtab只是一个以NULL结尾的字符串数组,包含所有二进制文件中所有节的名称


程序头

编辑

提供了二进制文件的段视图

ELF包括零或多个节,实际上就是把这些节捆绑成单个块

段提供的可执行视图,只有二进制文件会用到

p_type字段

标识了段的类型

主要类型包括PT_LOAD,PT_DYNAMIC,PT_INFERP

PT_LOAD类型的段会在创建进程时加载到内存中

PT_INFERP类型的段包含了.interp节,该节提供了加载二进制文件的解释器的名称

PT_DYNAMIC包含了.dynamic节,该节告诉解释器如何解析二进制文件用于执行

p_flags字段

指示了段在运行时的访问权限

有三种重要的类型

PF_X(可执行),PF_W(可写),PF_R(可读)

p_offset、p_vaddr、p_paddr、p_filesz和p_memsz字段

改段的起始文件偏移量,加载的虚拟地址以及段大小

p_align字段

指定了段所需的内存对齐方式(字节为单位)

本文介绍了ELF文件的各部分

编辑

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。