利用readelf详解elf

查看readelf选项

readelf -h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Options are:
-a --all Equivalent to: -h -l -S -s -r -d -V -A -I
-h --file-header Display the ELF file header
-l --program-headers Display the program headers
--segments An alias for --program-headers
-S --section-headers Display the sections' header
--sections An alias for --section-headers
-g --section-groups Display the section groups
-t --section-details Display the section details
-e --headers Equivalent to: -h -l -S
-s --syms Display the symbol table
--symbols An alias for --syms
--dyn-syms Display the dynamic symbol table
-n --notes Display the core notes (if present)
-r --relocs Display the relocations (if present)
-u --unwind Display the unwind info (if present)
-d --dynamic Display the dynamic section (if present)
-V --version-info Display the version sections (if present)
-A --arch-specific Display architecture specific information (if any)
-c --archive-index Display the symbol/file index in an archive
-D --use-dynamic Use the dynamic section info when displaying symbols
-x --hex-dump=<number|name>
Dump the contents of section <number|name> as bytes
-p --string-dump=<number|name>
Dump the contents of section <number|name> as strings
-R --relocated-dump=<number|name>
Dump the contents of section <number|name> as relocated bytes
-z --decompress Decompress section before dumping it
-w[lLiaprmfFsoRtUuTgAckK] or
--debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
=frames-interp,=str,=loc,=Ranges,=pubtypes,
=gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
=addr,=cu_index,=links,=follow-links]
Display the contents of DWARF debug sections
--dwarf-depth=N Do not display DIEs at depth N or greater
--dwarf-start=N Display DIEs starting with N, at the same depth
or deeper
-I --histogram Display histogram of bucket list lengths
-W --wide Allow output width to exceed 80 characters
@<file> Read options from <file>
-H --help Display this information
-v --version Display the version number of readelf

下面根据选项参数来一个一个解析,以32位为例,64位类似。

ELF文件头

readelf -h filename

ELF header数据结构如下(52字节):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define EI_NIDENT   16

typedef struct {
unsigned char e_ident[EI_NIDENT]; ##magic魔数
ELF32_Half e_type; ##类别
ELF32_Half e_machine; ##系统架构:3(Intel 80386)
ELF32_Word e_version; ##版本:2(可执行文件)
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_shstrndx; ##字符串表索引节头
} Elf32_Ehdr;

其中数据类型介绍如下:

名称 长度 对齐方式 用途
Elf32_Addr 4 4 无符号程序地址
Elf32_Half 2 2 无符号半整型
Elf32_Off 4 4 无符号文件偏移
Elf32_Sword 4 4 有符号大整型
Elf32_Word 4 4 无符号大整型
unsigned char 1 1 无符号小整型

magic介绍

1
2
3
4
5
6
前四字节:\x7F、'E'、'L'、'F'  文件标识
第五字节:文件类别,0(无效类型)、1(32位)、2(64位)
第六字节:数据编码,0(无效编码)、1(小端)、2(大端)
第七字节:文件版本,1(当前版本)
第八字节:补齐字节开始处
之后魔数:留用

程序头部表

readelf -l filename

程序头数据结构如下(32字节):

1
2
3
4
5
6
7
8
9
10
typedef struct {
ELF32_Word p_type;
ELF32_Off p_offset;
ELF32_Addr p_vaddr;
ELF32_Addr p_paddr;
ELF32_Word p_filesz;
ELF32_Word p_memsz;
ELF32_Word p_flags;
ELF32_Word p_align;
} Elf32_Phdr;

节区头部表

readelf -S filename

该结构用于定位 ELF 文件中的每个节区的具体位置。

节区头数据结构如下(40字节):

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct {
Elf32_Word sh_name; ## 节头部字符串表节区的索引
Elf32_Word sh_type; ## 节类型
Elf32_Word sh_flags; ## 节标志,用于描述属性
Elf32_Addr sh_addr; ## 节的内存映像
Elf32_Off sh_offset; ## 节的文件偏移
Elf32_Word sh_size; ## 节的长度
Elf32_Word sh_link; ## 节头部表索引链接
Elf32_Word sh_info; ## 附加信息
Elf32_Word sh_addralign; ## 节对齐约束
Elf32_Word sh_entsize; ## 固定大小的节表项的长度
} Elf32_Shdr;

下面看看几个重要的节

.dynsym

readelf -s filename

其数据结构如下(16字节):

1
2
3
4
5
6
7
8
typedef struct{
Elf32_Word st_name; // Symbol name(string tbl index)
Elf32_Addr st_value; // Symbol value
Elf32_Word st_size; // Symbol size
unsigned char st_info; // Symbol type and binding
unsigned char st_other; // Symbol visibility under glibc>=2.2
Elf32_Half st_shndx; // Section index
} Elf32_Sym;

.rel.plt和.rel.dyn

readelf -r filename

.rel.plt节是用于函数重定位,.rel.dyn节是用于变量重定位

对应数据结构如下(8字节):

1
2
3
4
typedef struct {
Elf32_Addr r_offset; // 对于可执行文件,此值为虚拟地址
Elf32_Word r_info; // 符号表索引
} Elf32_Rel;

.dynamic

readelf -d filename

动态链接的ELF文件的动态符号表

其中Tag对应着每个节。比如JMPREL对应着.rel.plt

其数据结构如下(12字节):

1
2
3
4
5
6
7
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
-------------本文结束感谢您的阅读-------------