ELF (Executable and Linkable Format): 是一种用于 可执行文件
、目标文件
和 库
的文件格式,类似于 Windows 下的 PE 文件格式。
ELF 主要包括三种类型的文件:
- 可重定位文件 (relocatable): 编译器和汇编器产生的
.o
文件,由 Linker 处理。 - 可执行文件 (executable): Linker 对
.o
文件进行处理后输出的文件,代表进程映像。 - 共享对象文件 (shared object): 动态库文件,通常是
.so
文件。
ELF 文件包含多个段,每个段承担不同的作用。以下是一些入门级 PWN 可能需要用到的段(仅介绍这些基本段):
- .text: 用于保存程序中的代码片段。
- .data: 用于保存已经初始化的全局变量和局部变量。
- .bss: 用于保存未初始化的全局变量和局部变量。
- .plt: 用于链接和跳转到对应的 .got 表。
- .got.plt: 存储对应函数的真实地址的表。
- .rodata: 只读数据
- .init: 程序初始化和终止的代码
ELF 文件中的段在程序执行前会被加载到内存中,然后在计算机内存中
一个程序可以认为由bss段
、data段
、text段
三个部分组成的。
text段
和data段
都存在可执行文件当中,程序执行时,系统从可执行文件中加载至内存
而bss段
在可执行文件中只是一个符号用于占位,由系统根据其符号进行初始化
如何加载:
.text 段
- 代码段 (code segment): 用来存放
程序执行的代码
。 - 这个段的大小在程序执行之前就已经确定,因为编译好的程序代码量一般是固定的。
- 该段通常有读和执行权限,但一般禁止修改(当然,也有部分特殊架构允许修改代码段)。
- 在代码段中,可能也包含一些常数变量,例如字符串。
.data 段
- 数据段 (data segment): 用来存放已经
初始化的全局变量
。 - 数据段属于静态内存分配,即被程序分配后大小不再改变。
例子:
#include <stdio.h>
int str[30] = "i_am_xidp_and_i_love_pwn";
int main() {
printf("%s", str);
return 0;
}
在上述例子中,已经被赋值好的数据 str
会被放在 .data 段中。由于其大小是固定的,因此 .data 段中的数据也是固定大小的。
.bss 段
- bss 段 (bss segment): 用于存放程序中未初始化的全局变量。
- 和 .data 段一样,属于静态内存分配。
例子:
#include <stdio.h>
int str[30];
int main() {
scanf("%s", str);
printf("%s", str);
return 0;
}
.bss 段本身不会占用 ELF 文件的实际大小,它在 ELF 等可执行文件中只是一个符号用于占位。程序执行时,会根据这个符号在计算机中分配相应的内存大小。
数据区: .data 段和 .bss 段通常被称为数据区。
参考文献:
Linux可执行文件格式-ELF结构详解 - 我叫平沢唯 - 博客园 (cnblogs.com)
PWN入门(1-1-2)-bss段、data段、text段、堆(heap)和栈(stack) (yuque.com)