二进制安全:ELF文件深度分析Linux二进制代码审计

Posted 鸿渐之翼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二进制安全:ELF文件深度分析Linux二进制代码审计相关的知识,希望对你有一定的参考价值。

目录:

认识ELF文件格式

程序的装载->ELF文件程序头表的解析(程序头表)

调试器符号表解析->ELF文件符号表的解析(.symtab节)符号表

认识ELF文件格式:

在这里插入图片描述
首先我们要了解什么是ELF
ELF(Executable and Linkable Format)
ELF是Linux系统下常用的一种可执行文件、对象、共享的标准文件格式
内核中处理ELF相关代码参考:fs/binfmt_elf.c
在这里插入图片描述ELF文件头部:
ELF Header 永远位于ELF文件最开始的地方,固定长度(ELF32,ELF64)

如何达到ELF头部信息

readelf -h filename	

在这里插入图片描述

程序头表(可选择)与节头表

程序只有是Linux或者MacOS等支持ELF文件的系统才能使用可选择的程序头表,节头表对不同的节进行索引
以上的程序作为例子分析:这是一个64位的程序
值得关注的是 Entry point address :0x9a0
程序头表位置
Start of program headers: 64 (bytes into file)
节头表位置
Start of section headers: 11224 (bytes into file)

64 bytes就是ELF头的 大小
Size of this header: 64 (bytes)

节头表的作用(Section Header):

解析节头表的命令:

readelf -l filename

在这里插入图片描述

在这里插入图片描述
文件中的 哪一部分(节)
搬到内存中的哪个位置(段)

节头表索引各个表

解析符号表+字符串表

readelf -s filename

某全局变量或函数(如,‘‘main’’)对应的内存的哪个地址

目前位置我们已经初步了解了ELF文件,下面是技术内容:

Segment:
包含:加载地址、文件范围、内存权限、对齐方式
segment为执行程序分配内存信息
Section:
告诉链接器程序的每一部分是做什么的。
Section类型,文件中的位置,大小信息
Segment与Section的区别:
相同的权限Section中会放入相同的Segment
.text与.rodata section
一个Segment包含许多Section

标题常见的ELF文件

可执行文件(ET_EXEC)
包含Segment
对象文件(ET_REL, * o)
包含Section
动态库(ET_DYN,*.so)
包含Segment和Section

1.ELF文件类型

ET_NONE
这个文件类型不确定或者意味着未被定义。
ET_REL
重定向文件。ELF类型标定为relocatable,也被称为目标文件。
可重定位目标文件通常是还未被链接到的可执行文件的一段位置独立的代码(postion independent code)。编译完成代码之后,生成.o文件这个文件包含了创建可执行文件所需要的代码与数据。
ET_EXEC
可执行文件。ELF类型为executable,表明这个文件被标记为可执行文件。
ET_DYN
共享目标文件。ELF类型为dynamic,意味着该文件被标记为一个动态的可链接的目标文件,也称为共享库。这类共享库会在程序运行时被装在链接到程序的进程镜像中。
ET_CORE
核心文件。在程序崩溃或者kernel进程反馈一个SIGEGV信号时,会在核心文件中记录。

2.ELF文件结构介绍
ELF头部文件结构:

#define EI_NIDENT 16
        typdef struct{
        unsigned char E_ident[EI_NIDENT];
        uint16_t      e_type;
        uint16_t      e_machine;
        uint32_t      e_version;
        FlfN_Addr     e_entry;
        ElfN_Off      e_phoff;
        ElfN_Off      e_shoff;
        uint32_t      e_falgs;
        uint16_t      e_ehsize;
        uint16_t      e_phentsize;
        uint16_t      e_phnum;
        uint16_t      e_shentsize;
        uint16_t      e_shnum;
        uint16_t      e_shstrndx;
        }ElfN_Ehdr;

ELF程序头
程序装载必须一个部分。段(segment)是在内核装载时被解析的,描述了磁盘上可执行文件的内存布局,以及如何映射内存的。
Elf32_Phdr 结构体:

typdef struct {
      uint32_t p_type; (segment type)
      Elf32_Off p_offset; (segment offset)
      Elf32_Addr p_vaddr; (segment virtual address)
      Elf32_Addr p_padder; (segment physical address)
      uint32_t p_filesz; (sizeof segment inthe files)
      uint32_t p_memsz;  (size of segment in momory)
      uint32_t p_flags;  (segment flags, I.E execute|read|write)
      uint32_t p_align; (segment alignment in memory)
      }Elf32_Phdr;

PT_LOAD段
一个可执行文件至少包含PT_LOAD段。
存放代码的text段;
存放全局变量的动态链接信息data段。
安全隐患:
可以将text段权限设置为PF_X | PF_R (读和可执行)
data段权限设置成PF_W | PF_R (读和写)
被感染千面人病毒(Polymorphic virus)文件的text段或data段的权限可能会被修改。
PT_DYNAMIC动态段的Phdr
32位ELF文件的动态段结构:

typedf struct{
Elf32_Sword d_tag;
union{
Elf32_Word d_val;
Elf32_Addr d_ptr;
}d_un;
|Elf32_Dyn;

PT_NOTE
PT_NOTE 类型的段可能保存了与特定供应商或者系统的附加信息。
有时候供应商或者系统构建者,需要在目标文件上标记特定的信息,以便于其他程序对一致性、兼容性等进行检查。
PT_INTERP
PT_INTEERP 段只将位置和大小信息存放一个以null为终止符的字符

下面通过一个程序展示如何利用以上结构中的字段映射一个ELF文件节头
节头(section header)
色即是空,空不是色。
段与节的区别?
段不是节,节不是段。
32位ELF节头的结构:

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

.text节
.text节是保存了程序代码指令的代码节。一段可执行程序。
.rodata节
.rodata节保存了只读的数据
只能在text段找到.rodata节。由于.rodata只读,因此类型为SHT_PROGBITS
.plt节
过程链接表(Procedure Linkage Table,PLT)
.data节
data节位于data段中,保存了初始化的全局变量等数据。由于其保存了程序的变量数据,因此类型被记标为SH_PROGBITS
.bss节
.bss节保存了为进行初始化的全局数据,是data段的一部分。
.got.plt节
.got保存了全局偏移表。如果攻击者获得了堆或者.bss漏洞的一个指针大小的写原,就可以堆该节任意进行修改。
.dynsym节
该节保存在text段中。保存了共享导入的动态符号信息。

以上是关于二进制安全:ELF文件深度分析Linux二进制代码审计的主要内容,如果未能解决你的问题,请参考以下文章

ELF二进制分析静态与动态。汇编代码如何?指令内存映射的变化?

ELF文件加载与动态链接

libelf 破坏 ARM elf 二进制文件

可执行文件格式elf和bin

手写ELF结构解析工具

ELF文件加载与动态链接