对学习到ELF文件结构的相关知识做一个简单的梳理,这些知识主要来自自己文件和代码的翻阅和其他博客,做提醒作用,想真的理解还请翻阅相关源码和结合手上的so慢慢翻看理解
一、ELF文件概览:
我们将图片以左右两边的箭头做分组它们分别代表了,ELF文件读取的两种不同视图,左侧为链接视图,是ELF文件由链接角度的解读,右侧为执行视图,是ELF文件由执行或加载(dlopen())角度的解读。由上图可知我们可以将一个ELF文件分为4部分:
- ELF Header 整个ELF的文件头 用于描述整个文件的概况
- Program Header Table:用于描述各Segment所包含的属性信息操作系统在执行过程中通过这些信息在进程所属的逻辑内存中分配内存并为这些内存添加对应的操作权限。
- Sections or Segments 因为解读的不同此处可以被解读为Sections或者Segments 虽解读方式不同但在进程中指向相同的内存,故此处先用or解释关于二者之间的关系与异同我会在后面介绍
- Section Header table 包含了文件中不同的section的定义信息,除此之外从执行视图来看,Section Header table也是一个Segment 属性为Dynamic
在讲解Section和Segment的关系前我们先上一张图
由图请先对二者有一个清晰地认识,之后我们来逐条分析:
- 二者在解读方式不同时可以忽略对方:
因Section Segment的解读方式不同所以我们可以在用一种方式的解读中忽略另一种,例如在运行阶段可以忽略Section的存在,同理在链接阶段可以忽略Segment
2.Segment在内存角度看包含section:
Program Hear中存储着Segment大小和操作权限的定义,故在加载阶段加载器通过这些定义来为系统分配内存和内存所属权限,如果有两个Section有着相同的权限需求那么完全可以放在同一个Segment中,所以我们可以推测Segment和Section在内存中为包含关系,结合逆向工具查看发现结论一致
3.作用及定位不同:
Segment作为运行时结构并不需要过多的属性 只需要圈定大小及权限,剩下的交由线程进行执行即可,而Section作为链接时结构则需要为不同的Section圈定角色用于链接,其中用作函数导出、依赖函数重定位的几部分尤为重要
二、各部分定义分析
各种C语言类型的定义:
名称 |
大小 |
说明 |
Elf32_Addr |
4 |
无符号程序地址 |
Elf32_Half |
2 |
无符号中等整数 |
Elf32_Off |
4 |
无符号文件偏移 |
Elf32_SWord |
4 |
有符号大整数 |
Elf32_Word |
4 |
无符号大整数 |
unsigned char |
1 |
无符号笑整数 |
各部分定义,极简略想细看看结尾大图
- ELF Header:
typedef struct {
unsigned char e_ident[16];
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_shstr