ELF-如何学习
研究 ELF(Executable and Linkable Format) 文件格式是理解热补丁技术(尤其是用户态热补丁)的关键基础。ELF 是 Linux 系统中可执行文件、共享库(.so
)和目标文件(.o
)的标准格式。以下是系统学习 ELF 文件格式的路径和资源建议:
1. 基础知识准备
1.1 理解 ELF 的核心概念
- ELF 文件类型:
- 可执行文件(Executable):可直接运行的程序(如
/bin/bash
)。 - 共享对象(Shared Object):动态链接库(如
.so
文件)。 - 可重定位文件(Relocatable):编译生成的中间目标文件(
.o
文件)。
- 可执行文件(Executable):可直接运行的程序(如
- ELF 结构组成:
- ELF Header:文件头,描述文件类型、架构、入口地址等元信息。
- Program Header Table:程序头表,定义如何将文件加载到内存(对可执行文件关键)。
- Section Header Table:节头表,描述文件中的各个节(Section)的详细信息。
- Sections:实际存储代码、数据、符号表、重定位信息等的区域(如
.text
,.data
,.symtab
)。
1.2 核心数据结构
- ELF Header:通过
readelf -h <file>
查看。- 关键字段:
e_type
(文件类型)、e_entry
(入口地址)、e_phoff
(程序头表偏移)、e_shoff
(节头表偏移)。
- 关键字段:
- Program Header:描述段(Segment)信息,用于加载到内存。
- 关键字段:
p_type
(段类型,如PT_LOAD
)、p_offset
(文件内偏移)、p_vaddr
(虚拟地址)。
- 关键字段:
- Section Header:描述节(Section)信息。
- 关键字段:
sh_name
(节名称)、sh_type
(类型,如SHT_PROGBITS
)、sh_addr
(内存地址)。
- 关键字段:
2. 学习资源推荐
2.1 官方文档与书籍
- ELF 官方标准:
- 阅读 ELF-64 Object File Format(PDF),这是最权威的规范文档。
- 书籍:
- 《Linkers and Loaders》(John R. Levine):讲解链接与加载过程,涵盖 ELF 的实践应用。
- 《程序员的自我修养:链接、装载与库》:中文经典,深入浅出。
2.2 在线教程与工具
- 入门教程:
- ELF 文件格式详解(适合快速上手)。
- ELF 101(分三部分讲解)。
- 工具实践:
readelf
:Linux 自带的 ELF 分析工具(例如readelf -S <file>
查看节头表)。objdump
:反汇编工具(如objdump -d <file>
查看代码段)。hexdump
或xxd
:直接查看二进制内容。nm
:查看符号表(如nm -D libfoo.so
)。
2.3 动态链接与加载
- 动态链接过程:
- 理解
LD_PRELOAD
、dlopen()
、dlsym()
的工作原理。 - 学习 PLT(Procedure Linkage Table) 和 GOT(Global Offset Table) 的机制。
- 理解
- 关键节(Sections):
.dynamic
:动态链接信息。.dynsym
:动态符号表。.rela.dyn
和.rela.plt
:重定位表。
3. 实践路径
3.1 手动分析 ELF 文件
-
查看 ELF 头:
readelf -h /bin/ls
- 观察文件类型(
EXEC
)、入口地址、节头表和程序头表的位置。
- 观察文件类型(
-
分析节头表:
readelf -S /bin/ls
- 找到
.text
(代码)、.data
(初始化的全局变量)、.rodata
(只读数据)、.symtab
(符号表)等关键节。
- 找到
-
分析程序头表:
readelf -l /bin/ls
- 查看哪些段(Segment)会被加载到内存(如
LOAD
类型)。
- 查看哪些段(Segment)会被加载到内存(如
-
查看符号表:
nm /bin/ls # 静态符号表 nm -D /lib/x86_64-linux-gnu/libc.so.6 # 动态符号表
3.2 编写代码解析 ELF
- 使用
libelf
或elfutils
库(C/C++):- 尝试编写程序读取 ELF 头、遍历节和符号表。
- Python 工具:
- 使用
pyelftools
库(示例代码见其 GitHub):from elftools.elf.elffile import ELFFile with open('test.o', 'rb') as f:elf = ELFFile(f)print("Entry point: 0x{:x}".format(elf.header['e_entry']))
- 使用
3.3 深入动态链接机制
- GOT/PLT Hook 实验:
- 编写一个简单的共享库
libfoo.so
,通过LD_PRELOAD
覆盖其函数。 - 使用
objdump -d libfoo.so
观察 PLT 和 GOT 条目。
- 编写一个简单的共享库
- 重定位分析:
- 修改共享库中的一个函数,观察
.rela.plt
中的重定位条目如何变化。
- 修改共享库中的一个函数,观察
4. 热补丁相关的 ELF 重点
4.1 关键知识点
- 符号表(Symbol Table):
- 热补丁需要替换函数符号,需理解
st_name
(符号名)、st_value
(地址)、st_shndx
(所属节)。
- 热补丁需要替换函数符号,需理解
- 重定位表(Relocation Table):
- 热补丁需处理重定位信息(如
R_X86_64_JUMP_SLOT
类型)。
- 热补丁需处理重定位信息(如
- 动态段(.dynamic):
- 包含动态链接所需的依赖库、符号版本等信息。
- 代码段(.text)与数据段(.data):
- 热补丁需确保补丁代码的地址与原代码的兼容性。
4.2 实践场景
- 函数替换:
- 通过修改 GOT 表项或 PLT 条目,将原函数地址替换为补丁函数地址。
- 代码注入:
- 在 ELF 文件中插入新的代码段,并通过重定位绑定到目标函数。
5. 后续方向
- 结合热补丁工具源码:
- 研究
syscare
或kpatch
的代码,观察其如何解析和修改 ELF 文件。
- 研究
- 调试与反汇编:
- 使用
gdb
动态调试进程,观察内存中 ELF 段的加载和符号解析过程。
- 使用
- 安全加固:
- 学习如何防止 ELF 注入攻击(如校验节头的完整性)。
6. 推荐学习资料汇总
- 工具:
readelf
,objdump
,nm
,gdb
,strace
。
- 代码库:
- pyelftools、libelf。
- 文章:
- How To Write A Shared Library(Ulrich Drepper)。
- PLT and GOT - The Key to Code Sharing and Dynamic Libraries。
通过以上步骤,你可以逐步掌握 ELF 文件格式的核心原理,并为热补丁开发打下坚实基础。实践中建议结合具体的热补丁场景(如替换函数、修改符号),逐步深入 ELF 的细节。