ELF文件格式

简介: ELF文件格式

二进制分析

什么是漏洞

漏洞的英文是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文件的各部分

相关文章
|
测试技术
elf格式转换为hex格式文件的两种方法
这周工作终于不太忙了,可以写点笔记总结一下了。 之前的文章如何在Keil-MDK开发环境生成Bin格式文件,介绍了如何在Keil开发环境使用fromelf软件,将生成的axf文件转换为bin文件,这次我们再来介绍一下如何将elf文件转换为hex文件。
1722 0
|
12月前
|
Unix
ELF文件格式入门
ELF(Executable and Linking Format),即“可执行可连接格式”,最初由 UNIX系统实验室做为应用程序二进制接口(ABI)的一部分而制定和发布。简单说就是一种文件格式。
ELF文件格式入门
|
Linux 数据安全/隐私保护
使用ofd6x工具解析elf文件
使用ofd6x工具解析elf文件
142 0
使用ofd6x工具解析elf文件
|
存储 编译器 Linux
BIN、HEX、AXF、ELF文件格式有什么区别
BIN、HEX、AXF、ELF文件格式有什么区别
193 0
BIN、HEX、AXF、ELF文件格式有什么区别
|
编译器 Linux Android开发
【Android 逆向】ELF 文件格式 ( ELF 文件简介 | ELF 文件结构 )
【Android 逆向】ELF 文件格式 ( ELF 文件简介 | ELF 文件结构 )
269 0
【Android 逆向】ELF 文件格式 ( ELF 文件简介 | ELF 文件结构 )
|
编译器 Android开发
【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )(二)
【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )(二)
143 0
【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )(二)
|
Android开发
【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )(一)
【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )(一)
115 0
【Android 逆向】ELF 文件格式 ( ELF 文件头 | ELF 文件头标志 | ELF 文件位数 | ELF 文件大小端格式 )(一)
|
架构师 Android开发
【Android 逆向】ELF 文件格式 ( ELF 文件类型 | ELF 文件对应 CPU 架构 | ELF 目标文件版本 | 可执行程序起始地址 )
【Android 逆向】ELF 文件格式 ( ELF 文件类型 | ELF 文件对应 CPU 架构 | ELF 目标文件版本 | 可执行程序起始地址 )
156 0
【Android 逆向】ELF 文件格式 ( ELF 文件类型 | ELF 文件对应 CPU 架构 | ELF 目标文件版本 | 可执行程序起始地址 )