-
-
[原创] ELF文件结构浅析-解析器和加载器实现
-
发表于: 2024-11-25 21:58 4080
-
近期冲浪刷到大佬博客ELF文件格式, 心血来潮
网上有不少ELF文件结构相关的文章,但大都介绍原理,具体的代码实现并不多(或许是因为有开源代码)
然而阅读开源代码不是我的强项(看的头大), 于是依据当年学习PE文件结构的思路,学习ELF文件格式
仿照 readelf 的输出结果编写解析器, 最后编写了简单的ELF加载器
代码支持x86和x64的ELF文件:
解析器针对x86/x64有两套实现, 支持解析x86和x64平台的ELF文件
加载器依赖编译环境,只能加载对应平台的ELF文件,要分别编译x86和x64的加载器
内容讲解演示主要以x86为主
环境&工具:
附件:
由于本人水平有限, 内容错误之处还望大佬多多包涵, 批评指正
ELF是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的,也是Linux的主要可执行文件格式, 全称是Executable and Linking Format,这个名字相当关键,包含了ELF所需要支持的两个功能——执行和链接
ELF文件包含3大部分,ELF头,ELF节,ELF段:
节头表指向节, 类似PE的节表, 描述各个节区的信息
程序头表描述段信息,一个段可以包含多个节,指导ELF文件如何映射至文件
在OBJ文件中,段是可选的,在可执行文件中,节是可选的,但NDK编译的ELF文件同时有段和节
ELF文件封装了部分数据类型
可以发现,32和64位定义的数据结构仅有Addr和Off有位宽差距,我们可以定义对应的通用类型
使用gcc分别编译32/64位的elf可执行文件用于测试
编写ELF解析器/加载器前,定义文件读取函数
读取指定路径文件,返回字节指针和读取文件大小
定义在elf.h中
可以使用readelf查看
16字节ELF标识,前4字节是ELF文件标识"\x7fELF",不可修改
010editor中解析如下
e_ident[EI_CLASS]
该字节指明了文件类型
Android系统不检查该字节,通过判断指令集v7a/v8a确定是32或64位
IDA检查该字节,如果修改了这个字节,IDA就无法反汇编
e_ident[EI_DATA]
该字节指明了目标文件的数据编码格式(大小端序)
Android不检查该字节,默认小端序; IDA检查该字节,如果修改该字节则IDA无法正确反汇编
e_ident[EI_VERSION]
ELF文件头的版本
2字节,表明目标文件属于哪种类型
Android5.0后,可执行文件全部为so,这个标志只能为03不可修改
2字节,该字段用于指定ELF文件适用的处理器架构,部分定义如下, 对于intel,固定为EM_386
4字节,指明目标文件版本
Android不检查该字段,IDA检查,但对反汇编无影响
4或8字节,程序入口点(OEP) RVA, 如果e_type=2 即可执行程序, 则该字段为VA; 如果是so,则为0
4或8字节,程序头表偏移FOA,如果没有程序头表则该字段为0
4或8字节,节头表偏移FOA,如果没有节头表则该字段为0
Android对抗中经常会删除节表
4字节标志,无用
2字节,ELF文件头大小
Android不检查,默认ELF Header大小为52字节; IDA检查,修改该字段只会产生警告不影响反汇编
2字节,表示程序头表每一个表项的大小
2字节,表示程序头表的表项数目
2字节,节头表表项大小
2字节,节头表表项个数
2字节,节头表中与节名表相对应表项的索引
根据枚举值,定义对应的字符串数组以打印相关信息
打印效果如下
类似PE文件的节表(IMAGE_SECTION_HEADER)
节表保存了节的基本属性,是ELF文件中除了文件头之外最重要的结构,编译器,链接器和装载器都依赖节表定位和访问各个节的属性
节表数组第0个元素固定为SHN_UNDEF, 节表成员结构定义如下
readelf查看节表
4字节,偏移值,通过ELF File Header.e_shstrndx拿到节表中节名称表对应项的索引
然后在节表中找到该项,找到sh_offset的文件偏移 sh_name+sh_offset即为该节名的字符串的FOA
4字节,指示节的类型, 定义如下
比较常见的节类型如下
4字节,由一系列标志bit位组成
SHF_WRITE 表示本节在进程中可写
SHF_ALLOC 表示本节在运行中需要占用内存
不是所有节都要占用实际内存,部分起控制作用的节在文件映射至内存时不需要占用
SHF_EXECINSTR 表示本节的内容是指令代码
SHF_MASKPROC 被该值覆盖的位都保留做特殊处理器扩展用
4字节,节的内存虚拟地址
4字节,节的FOA
4字节,段的大小
4字节,索引值
4字节,节的附加信息
根据节类型不同,sh_info和sh_link有不同的含义
4字节,段地址对齐值,假如为0或者1表示该段没有对齐要求; 假如为3表示对齐2^3=8
节的sh_addr必须能被sh_addralign整除,即sh_addr%sh_addralign=0
4字节,部分节的内容是一张表,每个表项的大小固定(例如符号表), 该字段指定其每个表项的大小
为0则表示不是这些表
打印结果如下
程序头表用于描述ELF文件如何映射到内存中,用段(segment)表示
定义如下
指定了程序头描述的段类型(或如何解析本程序头的信息)
段类型如下
段的文件偏移值
段的内存虚拟地址
段的内存物理地址, 由于多数现代操作系统的设计不可预知段的物理地址,故该字段多数情况下保留
段的文件大小
段的内存大小
段的属性
段的内存对齐值
打印结果如下
ELF 文件中有一些特定的节是预定义好的,其内容是指令代码或者控制信息
这些节专门为操作系统使用,对于不同的操作系统,这些节的类型和属性有所不同
ELF文件中有很多字符串,例如段名,变量名等, 由于字符串长度往往不固定,所以使用固定结构描述比较困难
常见做法是将字符串集中起来存放到一张字符串表,然后通过索引查表来引用字符串
常见的有:
.strtab(字符串表,保存普通字符串)
遍历section header, 查找type==SHT_STRTAB的即为字符串表 (包括段表字符串表)
.shstrtab(段表字符串表,保存段表用到的字符串)
获取该表可以通过ELF Header的e_shstrndx成员做索引,查找ELF Section Header Table
即p_shstrtab=ELFSectionHeaderTable[ELFHeader.e_shstrndx]
打印代码如下
符号表的作用是描述导入和导出符号,这里的符号可以是全局变量,函数,外部引用等
通过符号表和对应的字符串表可以得到符号名,符号大小,符号地址等信息
符号表表项结构
符号名, 字符串表的索引下标, 节表的sh_link说明了是在哪个字符串表中
符号对应的值, 和符号有关, 可能是绝对值,也可能是一个地址, 不同符号的含义不同
符号大小, 对于包含数据的符号, 是该数据类型的大小
例如一个double型的符号占用8字节,如果该值为0表示符号大小为0或未知
符号的类型和属性,高4bit标识了符号绑定(symbol binding), 低4bit标识了符号类型(symbol type),组成符号信息(symbol information)
有3个宏分别读取这三个属性值
符号绑定的合法属性如下
几个重要属性解释如下:
STB_LOCAL
该符号是本地符号,只出现在本文件中,在其他文件中无效
所以在不同文件中可以定义相同的符号名,不会互相影响
STB_GLOBAL
该符号是全局符号,当有多个文件被链接在一起时,在所有文件中该符号都是可见的
所以在一个文件中定义的全局符号,一定是在其他文件中需要被引用,否则无需定义为全局
STB_WEAK
弱符号,类似于全局符号,但优先级比global更低
STB_LOPROC~STB_HIPROC
为特殊处理器保留
几个重要符号解析如下
STT_NOTYPE
该符号类型未指定
STT_OBJECT
该符号是一个数据对象,例如变量,数组等
STT_FUNC
该符号是一个函数,或者其他的可执行代码
STT_SECTION
该符号和一个节相关联,用于重定位,通常具有STB_LOCAL属性
STT_FILE
该符号是一个文件符号,具有STB_LOCAL属性
STT_LOPROC~STT_HIPROC
为特殊处理器保留
低2位保存了符号可见性
符号所在的段
一般有两张重定位表:
.rel.plt 修复外部函数地址
.rel.dyn 修复全局变量地址
重定位表有SHT_REL, SHT_RELA, SHT_RELR三种类型,对应表项定义如下
注: Intel x86架构只使用REL重定位项, x64架构似乎只使用RELA重定位项, 在后续修复重定位表可以得知
重定位的位置
对于重定位文件而言,该值是待重定位单元在节中的偏移量
对于可执行文件或链接库文件而言,该值是待重定位单元的虚拟地址
给出了待重定位单元的符号表索引和重定位类型
获取信息的宏
SYM获取高24/32位, 是符号表索引, 指明符号
TYPE获取低8/32位, 是重定位类型
指定加数,用于计算需要重定位的域的值
Rela使用该字段显式地指出加数,Rel的加数隐含在被修改的位置中
一个重定位节(Relocation Section)需要引用另外两个节: 符号表和待修复节
重定位节节头的sh_info和sh_link分别指明了引用关系
不同目标文件中,重定位项的r_offset成员含义略有不同
重定位文件
r_offset指向待修改节的重定位单元偏移地址
可执行文件/共享目标文件
r_offset指向待修改单元的虚拟地址
重定位项用于描述如何修改以下的指令和数据域(被重定位域)
定义以下几种运算符号便于描述
常见重定位类型如下
将指定的符号地址设置为一个GOT表项
修复方法: elf加载后, 填入符号对应真实地址
用于动态链接的PLT表项
修复方法: elf加载后, 修改跳转地址为符号地址
相对偏移地址重定位
修复方法: 将offset指出的位置解引用,加上elf加载的基地址
全部的intel x86架构重定位类型如下
x64重定位类型定义如下
r_offset指定了待修复的地址,这是一个RVA, 需要将该地址存储的数据加上elf文件加载的基地址
例如readelf读取的重定位表信息如下
3ee8和3eec分别在init_array和fini_array段,均为RELATIVE类型重定位项
3fec, 3fe0,3fe4,3fe8,3ff0是GOT表项, 其中3fec (main_ptr) 是RELATIVE类型,其他均为GLOB_DAT类型
表项填充的函数为虚拟extern段中函数的地址,该段在内存中实际不存在
4000,4004是plt表项, 均为JUMP_SLOT类型, 400c是dso_handle, 为RELATIVE类型
got.plt表填充的也是外部函数地址,在虚拟extern段
在elf文件末尾,ida自动追加extern段(该段在内存中不存在,仅供分析)
综上所述,重定位有以下情况:
将待重定位地址处的内容解引用并加上elf加载的基地址即可
这种情况是针对elf文件内部变量绝对地址引用需要修复
例如RELATIVE类型
加载动态库,写入外部函数地址
针对外部引用地址修复
例如GLOB_DAT和JUMP_SLOT类型
如果目标文件参与动态链接,必定包含一个类型为 PT_DYNAMIC 的Program表项, 对应节名为 .dynamic (type=SHT_DYNAMIC)
动态段的作用是提供动态链接器所需要的信息,比如依赖哪些共享库文件,动态链接符号表的位置,动态链接重定位表的位置等
d_tag决定了如何对d_un解析
合法的d_tag值定义如下
该tag对应的即为elf文件依赖的动态库文件,使用d_val解析后得到索引值
通过索引查找.dynstr即可得到链接库名
动态段的sh_link字段是指向动态链接字符串表的索引值
另外通过d_tag==DT_STRTAB解析对应的d_val可以得到.dynstr的文件偏移值
d_val 代表整数值
d_ptr 代表进程空间的虚拟地址
解析规则如下
哈希表可用于查询导出函数, 有两种, 目前的elf文件主要是用GNU HASH表作为导出表
Hash表定义如下
Linux原始Elf Hash算法如下
ELF Hash Table根据符号名查找符号地址的流程如下
根据elfhash函数计算符号名的hash
index=buckets[hash%nbucket]
index即为符号在符号表中的索引
如果index==SHT_UNDEF(0)则未找到符号,结束
否则判断符号表中索引index的符号和目标符号是否相同
如果符号名不同则根据index从chains表找下一个符号索引,继续第3步
index=chains[index] (如果chains[index]==0说明不存在该符号)
代码表示如下:
手工查找流程示例:
由于x86_64下gcc编译的elf程序默认只使用gnu.hash,以Android NDK得到的64位so为例
找到.hash节,发现nbucket=nchain=0x36
根据elfhash计算bucket下标, index=hash%nbucket =48
由于bucket项大小为4字节,从0x960开始+48*4=0xA20
得到动态符号表下标为0xE(14), 查找符号表正好对应dlopen函数
Android的elfhash算法代码有所不同,但和原始elfhash等价
参考 https://cs.android.com/android/platform/superproject/+/android-4.1.2_r2.1:bionic/linker/linker.c
Elf Hash在Android又定义为为Sysv Hash,参考https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:external/musl/ldso/dynlink.c
GNU Hash表项如下
可以发现,GNU Hash并没有给出nchain字段,如何计算?
查找GNU Hash表的示意图如下:
chain表的虚线部分并不存在
除了导出符号之外的符号chain表并无必要保存,但chain表的索引和符号表要一一对应
所以chain表的理论起始地址=buckets+nbucket-symndx
但在文件的排列上,各项是连续的,chains有效内容仍然在buckets后方
chain表每个表项保存符号的哈希值
最低位为0时表示对应的符号有剩余哈希冲突项
为1时表示没有剩余冲突项
详细可参考ELF 通过 Sysv Hash & Gnu Hash 查找符号的实现及对比和ELF解析07_哈希表, 导出表
Android Linker的源码实现如下
ELF Program Header描述了ELF文件的哪些段需要映射到内存,ELF程序的加载流程如下:
将elf文件加载到内存中,成为filebuffer
根据program header,映射filebuffer至imagebuffer
这一步需要给予不同段正确的权限
重定位,修复全局变量地址和外部引用地址
根据elf加载的基地址修复全局变量地址
外部引用地址需要加载并遍历needed libso,根据符号查找函数真实地址并修复
跳转至入口点
分别编译loadelf32/64以加载x86/x64的elf文件
main.c
LoadELF.h
LoadELF.c
根据x86/x64不同环境,定义对应宏
效果如下
《程序员的自我修养》
ELF 通过 Sysv Hash & Gnu Hash 查找符号的实现及对比
#include <stdint.h>
typedef
uint16_t Elf32_Half;
typedef
uint16_t Elf64_Half;
/* Types for signed and unsigned 32-bit quantities. */
typedef
uint32_t Elf32_Word;
typedef
int32_t Elf32_Sword;
typedef
uint32_t Elf64_Word;
typedef
int32_t Elf64_Sword;
/* Types for signed and unsigned 64-bit quantities. */
typedef
uint64_t Elf32_Xword;
typedef
int64_t Elf32_Sxword;
typedef
uint64_t Elf64_Xword;
typedef
int64_t Elf64_Sxword;
/* Type of addresses. */
typedef
uint32_t Elf32_Addr;
typedef
uint64_t Elf64_Addr;
/* Type of file offsets. */
typedef
uint32_t Elf32_Off;
typedef
uint64_t Elf64_Off;
/* Type for section indices, which are 16-bit quantities. */
typedef
uint16_t Elf32_Section;
typedef
uint16_t Elf64_Section;
/* Type for version symbol information. */
typedef
Elf32_Half Elf32_Versym;
typedef
Elf64_Half Elf64_Versym;
#include <stdint.h>
typedef
uint16_t Elf32_Half;
typedef
uint16_t Elf64_Half;
/* Types for signed and unsigned 32-bit quantities. */
typedef
uint32_t Elf32_Word;
typedef
int32_t Elf32_Sword;
typedef
uint32_t Elf64_Word;
typedef
int32_t Elf64_Sword;
/* Types for signed and unsigned 64-bit quantities. */
typedef
uint64_t Elf32_Xword;
typedef
int64_t Elf32_Sxword;
typedef
uint64_t Elf64_Xword;
typedef
int64_t Elf64_Sxword;
/* Type of addresses. */
typedef
uint32_t Elf32_Addr;
typedef
uint64_t Elf64_Addr;
/* Type of file offsets. */
typedef
uint32_t Elf32_Off;
typedef
uint64_t Elf64_Off;
/* Type for section indices, which are 16-bit quantities. */
typedef
uint16_t Elf32_Section;
typedef
uint16_t Elf64_Section;
/* Type for version symbol information. */
typedef
Elf32_Half Elf32_Versym;
typedef
Elf64_Half Elf64_Versym;
ELF数据结构 | 原始类型 | 备注 |
---|---|---|
Elfn_Half | uint16_t | |
Elfn_Word | uint32_t | |
Elfn_Sword | int32_t | |
Elfn_Xword | uint64_t | |
Elfn_Sxword | int64_t | |
Elf32_Addr | uint32_t | 地址 |
Elf64_Addr | uint64_t | |
Elf32_Off | uint32_t | 文件偏移 |
Elf64_Off | uint64_t | |
Elfn_Section | uint16_t | 节索引 |
Elfn_Versym | uint16_t |
#include <stdio.h>
int
main(
int
argc,
char
* argv[]){
printf
(
"Hello ELF!\n"
);
return
0;
}
#include <stdio.h>
int
main(
int
argc,
char
* argv[]){
printf
(
"Hello ELF!\n"
);
return
0;
}
gcc -m32 -O0 main.c -o HelloELF32
gcc -m64 -O0 main.c -o HelloELF64
gcc -m32 -O0 main.c -o HelloELF32
gcc -m64 -O0 main.c -o HelloELF64
// 读取文件,返回buffer和读取字节数
uint8_t* readFileToBytes(
const
char
*fileName,
size_t
* readSize) {
FILE
*file =
fopen
(fileName,
"rb"
);
if
(file == NULL) {
printf
(
"Error opening file\n"
);
fclose
(file);
return
NULL;
}
fseek
(file, 0,SEEK_END);
size_t
fileSize =
ftell
(file);
fseek
(file, 0,SEEK_SET);
uint8_t *buffer = (uint8_t *)
malloc
(fileSize);
if
(buffer == NULL) {
printf
(
"Error allocating memory\n"
);
fclose
(file);
return
NULL;
}
size_t
bytesRead =
fread
(buffer, 1, fileSize, file);
if
(bytesRead!=fileSize) {
printf
(
"Read bytes not equal file size!\n"
);
free
(buffer);
fclose
(file);
return
NULL;
}
fclose
(file);
if
(readSize)
*readSize=bytesRead;
return
buffer;
}
// 读取文件,返回buffer和读取字节数
uint8_t* readFileToBytes(
const
char
*fileName,
size_t
* readSize) {
FILE
*file =
fopen
(fileName,
"rb"
);
if
(file == NULL) {
printf
(
"Error opening file\n"
);
fclose
(file);
return
NULL;
}
fseek
(file, 0,SEEK_END);
size_t
fileSize =
ftell
(file);
fseek
(file, 0,SEEK_SET);
uint8_t *buffer = (uint8_t *)
malloc
(fileSize);
if
(buffer == NULL) {
printf
(
"Error allocating memory\n"
);
fclose
(file);
return
NULL;
}
size_t
bytesRead =
fread
(buffer, 1, fileSize, file);
if
(bytesRead!=fileSize) {
printf
(
"Read bytes not equal file size!\n"
);
free
(buffer);
fclose
(file);
return
NULL;
}
fclose
(file);
if
(readSize)
*readSize=bytesRead;
return
buffer;
}
#define EI_NIDENT (16)
typedef
struct
{
unsigned
char
e_ident[EI_NIDENT];
/* Magic number and other info */
Elf32_Half e_type;
/* Object file type */
Elf32_Half e_machine;
/* Architecture */
Elf32_Word e_version;
/* Object file version */
Elf32_Addr e_entry;
/* Entry point virtual address */
Elf32_Off e_phoff;
/* Program header table file offset */
Elf32_Off e_shoff;
/* Section header table file offset */
Elf32_Word e_flags;
/* Processor-specific flags */
Elf32_Half e_ehsize;
/* ELF header size in bytes */
Elf32_Half e_phentsize;
/* Program header table entry size */
Elf32_Half e_phnum;
/* Program header table entry count */
Elf32_Half e_shentsize;
/* Section header table entry size */
Elf32_Half e_shnum;
/* Section header table entry count */
Elf32_Half e_shstrndx;
/* Section header string table index */
} Elf32_Ehdr;
//64位
typedef
struct
{
unsigned
char
e_ident[EI_NIDENT];
/* Magic number and other info */
Elf64_Half e_type;
/* Object file type */
Elf64_Half e_machine;
/* Architecture */
Elf64_Word e_version;
/* Object file version */
Elf64_Addr e_entry;
/* Entry point virtual address */
Elf64_Off e_phoff;
/* Program header table file offset */
Elf64_Off e_shoff;
/* Section header table file offset */
Elf64_Word e_flags;
/* Processor-specific flags */
Elf64_Half e_ehsize;
/* ELF header size in bytes */
Elf64_Half e_phentsize;
/* Program header table entry size */
Elf64_Half e_phnum;
/* Program header table entry count */
Elf64_Half e_shentsize;
/* Section header table entry size */
Elf64_Half e_shnum;
/* Section header table entry count */
Elf64_Half e_shstrndx;
/* Section header string table index */
} Elf64_Ehdr;
#define EI_NIDENT (16)
typedef
struct
{
unsigned
char
e_ident[EI_NIDENT];
/* Magic number and other info */
Elf32_Half e_type;
/* Object file type */
Elf32_Half e_machine;
/* Architecture */
Elf32_Word e_version;
/* Object file version */
Elf32_Addr e_entry;
/* Entry point virtual address */
Elf32_Off e_phoff;
/* Program header table file offset */
Elf32_Off e_shoff;
/* Section header table file offset */
Elf32_Word e_flags;
/* Processor-specific flags */
Elf32_Half e_ehsize;
/* ELF header size in bytes */
Elf32_Half e_phentsize;
/* Program header table entry size */
Elf32_Half e_phnum;
/* Program header table entry count */
Elf32_Half e_shentsize;
/* Section header table entry size */
Elf32_Half e_shnum;
/* Section header table entry count */
Elf32_Half e_shstrndx;
/* Section header string table index */
} Elf32_Ehdr;
//64位
typedef
struct
{
unsigned
char
e_ident[EI_NIDENT];
/* Magic number and other info */
Elf64_Half e_type;
/* Object file type */
Elf64_Half e_machine;
/* Architecture */
Elf64_Word e_version;
/* Object file version */
Elf64_Addr e_entry;
/* Entry point virtual address */
Elf64_Off e_phoff;
/* Program header table file offset */
Elf64_Off e_shoff;
/* Section header table file offset */
Elf64_Word e_flags;
/* Processor-specific flags */
Elf64_Half e_ehsize;
/* ELF header size in bytes */
Elf64_Half e_phentsize;
/* Program header table entry size */
Elf64_Half e_phnum;
/* Program header table entry count */
Elf64_Half e_shentsize;
/* Section header table entry size */
Elf64_Half e_shnum;
/* Section header table entry count */
Elf64_Half e_shstrndx;
/* Section header string table index */
} Elf64_Ehdr;
/
*
Legal values
for
e_type (
object
file
type
).
*
/
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_NUM 5 /* Number of defined types */
#define ET_LOOS 0xfe00 /* OS-specific range start */
#define ET_HIOS 0xfeff /* OS-specific range end */
#define ET_LOPROC 0xff00 /* Processor-specific range start */
#define ET_HIPROC 0xffff /* Processor-specific range end */
/
*
Legal values
for
e_type (
object
file
type
).
*
/
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_NUM 5 /* Number of defined types */
#define ET_LOOS 0xfe00 /* OS-specific range start */
#define ET_HIOS 0xfeff /* OS-specific range end */
#define ET_LOPROC 0xff00 /* Processor-specific range start */
#define ET_HIPROC 0xffff /* Processor-specific range end */
#define EM_NONE 0 /* No machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SUN SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola m68k family */
#define EM_88K 5 /* Motorola m88k family */
#define EM_IAMCU 6 /* Intel MCU */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 big-endian */
#define EM_S370 9 /* IBM System/370 */
#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
/* reserved 11-14 */
#define EM_PARISC 15 /* HPPA */
/* reserved 16 */
#define EM_NONE 0 /* No machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SUN SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola m68k family */
#define EM_88K 5 /* Motorola m88k family */
#define EM_IAMCU 6 /* Intel MCU */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 big-endian */
#define EM_S370 9 /* IBM System/370 */
#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
/* reserved 11-14 */
#define EM_PARISC 15 /* HPPA */
/* reserved 16 */
// Print ELF Header
char
ELF_Class[3][6] = {
"NONE"
,
"ELF32"
,
"ELF64"
};
char
ELF_Data[3][14] = {
"NONE"
,
"Little Endian"
,
"Big Endian"
};
char
objectFileType[7][7] = {
"NONE"
,
"REL"
,
"EXEC"
,
"DYN"
,
"CORE"
,
"LOPROC"
,
"HIPROC"
};
void
printELFHeader32(
const
Elf32_Ehdr* pElfHeader) {
printf
(
"ELF Header:\n"
);
printf
(
"\tMagic:\t"
);
for
(
int
i = 0; i < EI_NIDENT; i++) {
printf
(
"%02x "
, pElfHeader[i].e_ident[i]);
}
printf
(
"\n"
);
printf
(
"\t%-36s%s\n"
,
"Class:"
, ELF_Class[pElfHeader->e_ident[EI_CLASS]]);
printf
(
"\t%-36s%s\n"
,
"Data:"
, ELF_Data[pElfHeader->e_ident[EI_DATA]]);
printf
(
"\t%-36s%#x\n"
,
"Version:"
, pElfHeader->e_version);
printf
(
"\t%-36s%#x\n"
,
"Machine:"
, pElfHeader->e_machine);
printf
(
"\t%-36s%s\n"
,
"Type:"
, objectFileType[pElfHeader->e_type]);
printf
(
"\t%-36s%#x\n"
,
"Size Of ELF Header:"
, pElfHeader->e_ehsize);
printf
(
"\t%-36s%#x\n"
,
"Entry point:"
, pElfHeader->e_entry);
printf
(
"\t%-36s%#x\n"
,
"Start Of Program Headers:"
, pElfHeader->e_phoff);
printf
(
"\t%-36s%#x\n"
,
"Start Of Section Headers:"
, pElfHeader->e_shoff);
printf
(
"\t%-36s%#x\n"
,
"Size Of Program Headers:"
, pElfHeader->e_phentsize);
printf
(
"\t%-36s%#x\n"
,
"Number Of Program Headers:"
, pElfHeader->e_phnum);
printf
(
"\t%-36s%#x\n"
,
"Size Of Section Headers:"
, pElfHeader->e_shentsize);
printf
(
"\t%-36s%#x\n"
,
"Number Of Sections:"
, pElfHeader->e_shnum);
printf
(
"\t%-36s%d\n"
,
"Section Header String Table Index:"
, pElfHeader->e_shstrndx);
printf
(
"ELF Header End\n"
);
}
// Print ELF Header
char
ELF_Class[3][6] = {
"NONE"
,
"ELF32"
,
"ELF64"
};
char
ELF_Data[3][14] = {
"NONE"
,
"Little Endian"
,
"Big Endian"
};
char
objectFileType[7][7] = {
"NONE"
,
"REL"
,
"EXEC"
,
"DYN"
,
"CORE"
,
"LOPROC"
,
"HIPROC"
};
void
printELFHeader32(
const
Elf32_Ehdr* pElfHeader) {
printf
(
"ELF Header:\n"
);
printf
(
"\tMagic:\t"
);
for
(
int
i = 0; i < EI_NIDENT; i++) {
printf
(
"%02x "
, pElfHeader[i].e_ident[i]);
}
printf
(
"\n"
);
printf
(
"\t%-36s%s\n"
,
"Class:"
, ELF_Class[pElfHeader->e_ident[EI_CLASS]]);
printf
(
"\t%-36s%s\n"
,
"Data:"
, ELF_Data[pElfHeader->e_ident[EI_DATA]]);
printf
(
"\t%-36s%#x\n"
,
"Version:"
, pElfHeader->e_version);
printf
(
"\t%-36s%#x\n"
,
"Machine:"
, pElfHeader->e_machine);
printf
(
"\t%-36s%s\n"
,
"Type:"
, objectFileType[pElfHeader->e_type]);
printf
(
"\t%-36s%#x\n"
,
"Size Of ELF Header:"
, pElfHeader->e_ehsize);
printf
(
"\t%-36s%#x\n"
,
"Entry point:"
, pElfHeader->e_entry);
printf
(
"\t%-36s%#x\n"
,
"Start Of Program Headers:"
, pElfHeader->e_phoff);
printf
(
"\t%-36s%#x\n"
,
"Start Of Section Headers:"
, pElfHeader->e_shoff);
printf
(
"\t%-36s%#x\n"
,
"Size Of Program Headers:"
, pElfHeader->e_phentsize);
printf
(
"\t%-36s%#x\n"
,
"Number Of Program Headers:"
, pElfHeader->e_phnum);
printf
(
"\t%-36s%#x\n"
,
"Size Of Section Headers:"
, pElfHeader->e_shentsize);
printf
(
"\t%-36s%#x\n"
,
"Number Of Sections:"
, pElfHeader->e_shnum);
printf
(
"\t%-36s%d\n"
,
"Section Header String Table Index:"
, pElfHeader->e_shstrndx);
printf
(
"ELF Header End\n"
);
}
typedef
struct
{
Elf32_Word sh_name;
/* Section name (string tbl index) */
Elf32_Word sh_type;
/* Section type */
Elf32_Word sh_flags;
/* Section flags */
Elf32_Addr sh_addr;
/* Section virtual addr at execution */
Elf32_Off sh_offset;
/* Section file offset */
Elf32_Word sh_size;
/* Section size in bytes */
Elf32_Word sh_link;
/* Link to another section */
Elf32_Word sh_info;
/* Additional section information */
Elf32_Word sh_addralign;
/* Section alignment */
Elf32_Word sh_entsize;
/* Entry size if section holds table */
} Elf32_Shdr;
typedef
struct
{
Elf64_Word sh_name;
/* Section name (string tbl index) */
Elf64_Word sh_type;
/* Section type */
Elf64_Xword sh_flags;
/* Section flags */
Elf64_Addr sh_addr;
/* Section virtual addr at execution */
Elf64_Off sh_offset;
/* Section file offset */
Elf64_Xword sh_size;
/* Section size in bytes */
Elf64_Word sh_link;
/* Link to another section */
Elf64_Word sh_info;
/* Additional section information */
Elf64_Xword sh_addralign;
/* Section alignment */
Elf64_Xword sh_entsize;
/* Entry size if section holds table */
} Elf64_Shdr;
typedef
struct
{
Elf32_Word sh_name;
/* Section name (string tbl index) */
Elf32_Word sh_type;
/* Section type */
Elf32_Word sh_flags;
/* Section flags */
Elf32_Addr sh_addr;
/* Section virtual addr at execution */
Elf32_Off sh_offset;
/* Section file offset */
Elf32_Word sh_size;
/* Section size in bytes */
Elf32_Word sh_link;
/* Link to another section */
Elf32_Word sh_info;
/* Additional section information */
Elf32_Word sh_addralign;
/* Section alignment */
Elf32_Word sh_entsize;
/* Entry size if section holds table */
} Elf32_Shdr;
typedef
struct
{
Elf64_Word sh_name;
/* Section name (string tbl index) */
Elf64_Word sh_type;
/* Section type */
Elf64_Xword sh_flags;
/* Section flags */
Elf64_Addr sh_addr;
/* Section virtual addr at execution */
Elf64_Off sh_offset;
/* Section file offset */
Elf64_Xword sh_size;
/* Section size in bytes */
Elf64_Word sh_link;
/* Link to another section */
Elf64_Word sh_info;
/* Additional section information */
Elf64_Xword sh_addralign;
/* Section alignment */
Elf64_Xword sh_entsize;
/* Entry size if section holds table */
} Elf64_Shdr;
/* Legal values for sh_type (section type). */
#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
#define SHT_SYMTAB 2 /* Symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Relocation entries with addends */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Dynamic linking information */
#define SHT_NOTE 7 /* Notes */
#define SHT_NOBITS 8 /* Program space with no data (bss) */
#define SHT_REL 9 /* Relocation entries, no addends */
#define SHT_SHLIB 10 /* Reserved */
#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
#define SHT_INIT_ARRAY 14 /* Array of constructors */
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */
#define SHT_RELR 19 /* RELR relative relocations */
#define SHT_NUM 20 /* Number of defined types. */
#define SHT_LOOS 0x60000000 /* Start OS-specific. */
#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
#define SHT_SUNW_move 0x6ffffffa
#define SHT_SUNW_COMDAT 0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
#define SHT_HIOS 0x6fffffff /* End OS-specific type */
#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
#define SHT_LOUSER 0x80000000 /* Start of application-specific */
#define SHT_HIUSER 0x8fffffff /* End of application-specific */
/* Legal values for sh_type (section type). */
#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
#define SHT_SYMTAB 2 /* Symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Relocation entries with addends */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Dynamic linking information */
#define SHT_NOTE 7 /* Notes */
#define SHT_NOBITS 8 /* Program space with no data (bss) */
#define SHT_REL 9 /* Relocation entries, no addends */
#define SHT_SHLIB 10 /* Reserved */
#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
#define SHT_INIT_ARRAY 14 /* Array of constructors */
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */
#define SHT_RELR 19 /* RELR relative relocations */
#define SHT_NUM 20 /* Number of defined types. */
#define SHT_LOOS 0x60000000 /* Start OS-specific. */
#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
#define SHT_SUNW_move 0x6ffffffa
#define SHT_SUNW_COMDAT 0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
#define SHT_HIOS 0x6fffffff /* End OS-specific type */
#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
#define SHT_LOUSER 0x80000000 /* Start of application-specific */
#define SHT_HIUSER 0x8fffffff /* End of application-specific */
SHT_NULL
/
/
无效节
SHT_STRTAB
/
/
本节是字符串表 ELF文件可以有多个字符串表节
SHT_RELA
/
/
重定位节
SHT_HASH
/
/
表明本节包含一张哈希表 目前一个ELF文件最多只能有一张哈希表
SHT_DYNAMIC
/
/
表明本节包含动态链接信息 目前一个目标文件最多一个dynamic节
SHT_NOBITS
/
/
表明本节内容为空,不占用实际内存空间
SHT_REL
/
/
重定位节
SHT_DYNSYM
/
/
表明本节是符号表,同SHT_SYMTAB
SHT_NULL
/
/
无效节
SHT_STRTAB
/
/
本节是字符串表 ELF文件可以有多个字符串表节
SHT_RELA
/
/
重定位节
SHT_HASH
/
/
表明本节包含一张哈希表 目前一个ELF文件最多只能有一张哈希表
SHT_DYNAMIC
/
/
表明本节包含动态链接信息 目前一个目标文件最多一个dynamic节
SHT_NOBITS
/
/
表明本节内容为空,不占用实际内存空间
SHT_REL
/
/
重定位节
SHT_DYNSYM
/
/
表明本节是符号表,同SHT_SYMTAB
// Print ELF Section Headers
char
*getSectionTypeString(Elf_Word sectionType) {
switch
(sectionType) {
case
SHT_NULL:
return
"NULL"
;
case
SHT_PROGBITS:
return
"PROGBITS"
;
case
SHT_SYMTAB:
return
"SYMTAB"
;
case
SHT_STRTAB:
return
"STRTAB"
;
case
SHT_RELA:
return
"RELA"
;
case
SHT_HASH:
return
"HASH"
;
case
SHT_DYNAMIC:
return
"DYNAMIC"
;
case
SHT_NOTE:
return
"NOTE"
;
case
SHT_NOBITS:
return
"NOBITS"
;
case
SHT_REL:
return
"REL"
;
case
SHT_SHLIB:
return
"SHLIB"
;
case
SHT_DYNSYM:
return
"DYNSYM"
;
case
SHT_INIT_ARRAY:
return
"INIT_ARRAY"
;
case
SHT_FINI_ARRAY:
return
"FINI_ARRAY"
;
case
SHT_PREINIT_ARRAY:
return
"PREINIT_ARRAY"
;
case
SHT_GROUP:
return
"GROUP"
;
case
SHT_SYMTAB_SHNDX:
return
"SYMTAB_SHNDX"
;
case
SHT_RELR:
return
"RELR"
;
case
SHT_NUM:
return
"NUM"
;
case
SHT_LOOS:
return
"LOOS"
;
case
SHT_GNU_ATTRIBUTES:
return
"GNU_ATTRIBUTES"
;
case
SHT_GNU_HASH:
return
"GNU_HASH"
;
case
SHT_GNU_LIBLIST:
return
"GNU_LIBLIST"
;
case
SHT_CHECKSUM:
return
"CHECKSUM"
;
case
SHT_LOSUNW:
return
"LOSUNW"
;
case
SHT_SUNW_COMDAT:
return
"SUNW_COMDAT"
;
case
SHT_SUNW_syminfo:
return
"SUNW_syminfo"
;
case
SHT_GNU_verdef:
return
"GNU_verdef"
;
case
SHT_GNU_verneed:
return
"GNU_verneed"
;
case
SHT_GNU_versym:
return
"GNU_versym"
;
case
SHT_LOPROC:
return
"LOPROC"
;
case
SHT_HIPROC:
return
"HIPROC"
;
case
SHT_LOUSER:
return
"LOUSER"
;
case
SHT_HIUSER:
return
"HIUSER"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
* getSectionFlagStr(Elf_Word flags) {
switch
(flags) {
case
SHF_ALLOC:
return
" A"
;
case
SHF_WRITE:
return
" W"
;
case
SHF_WRITE | SHF_ALLOC:
return
" WA"
;
case
SHF_EXECINSTR:
return
" X"
;
case
SHF_ALLOC | SHF_EXECINSTR:
return
" AX"
;
case
SHF_MASKPROC:
return
"MKP"
;
default
:
return
" "
;
}
}
void
printElfSectionHeader32(
const
Elf32_Shdr* pSectionHeader,Elf_Half sectionNum,
const
char
* pStringTable) {
printf
(
"ELF Section Headers:\n"
);
printf
(
"\t[Nr] Name\t\t\tType\t\t\tAddr\t\tOffset\t\tSize\t\tEntSize\tFlag\tLink\tInfo\tAlign\n"
);
for
(
int
i = 0; i < sectionNum; i++) {
printf
(
"\t[%2d] %-20s"
, i, (
char
*) &pStringTable[pSectionHeader[i].sh_name]);
printf
(
"\t%-16s"
, getSectionTypeString(pSectionHeader[i].sh_type));
printf
(
"\t%08x"
, pSectionHeader[i].sh_addr);
printf
(
"\t%08x"
, pSectionHeader[i].sh_offset);
printf
(
"\t%08x"
, pSectionHeader[i].sh_size);
printf
(
"\t%x"
, pSectionHeader[i].sh_entsize);
printf
(
"\t%s"
, getSectionFlagStr(pSectionHeader[i].sh_flags));
printf
(
"\t%x"
, pSectionHeader[i].sh_link);
printf
(
"\t%x"
, pSectionHeader[i].sh_info);
printf
(
"\t%x\n"
, pSectionHeader[i].sh_addralign);
}
printf
(
"ELF Section Headers End\n"
);
}
// Print ELF Section Headers
char
*getSectionTypeString(Elf_Word sectionType) {
switch
(sectionType) {
case
SHT_NULL:
return
"NULL"
;
case
SHT_PROGBITS:
return
"PROGBITS"
;
case
SHT_SYMTAB:
return
"SYMTAB"
;
case
SHT_STRTAB:
return
"STRTAB"
;
case
SHT_RELA:
return
"RELA"
;
case
SHT_HASH:
return
"HASH"
;
case
SHT_DYNAMIC:
return
"DYNAMIC"
;
case
SHT_NOTE:
return
"NOTE"
;
case
SHT_NOBITS:
return
"NOBITS"
;
case
SHT_REL:
return
"REL"
;
case
SHT_SHLIB:
return
"SHLIB"
;
case
SHT_DYNSYM:
return
"DYNSYM"
;
case
SHT_INIT_ARRAY:
return
"INIT_ARRAY"
;
case
SHT_FINI_ARRAY:
return
"FINI_ARRAY"
;
case
SHT_PREINIT_ARRAY:
return
"PREINIT_ARRAY"
;
case
SHT_GROUP:
return
"GROUP"
;
case
SHT_SYMTAB_SHNDX:
return
"SYMTAB_SHNDX"
;
case
SHT_RELR:
return
"RELR"
;
case
SHT_NUM:
return
"NUM"
;
case
SHT_LOOS:
return
"LOOS"
;
case
SHT_GNU_ATTRIBUTES:
return
"GNU_ATTRIBUTES"
;
case
SHT_GNU_HASH:
return
"GNU_HASH"
;
case
SHT_GNU_LIBLIST:
return
"GNU_LIBLIST"
;
case
SHT_CHECKSUM:
return
"CHECKSUM"
;
case
SHT_LOSUNW:
return
"LOSUNW"
;
case
SHT_SUNW_COMDAT:
return
"SUNW_COMDAT"
;
case
SHT_SUNW_syminfo:
return
"SUNW_syminfo"
;
case
SHT_GNU_verdef:
return
"GNU_verdef"
;
case
SHT_GNU_verneed:
return
"GNU_verneed"
;
case
SHT_GNU_versym:
return
"GNU_versym"
;
case
SHT_LOPROC:
return
"LOPROC"
;
case
SHT_HIPROC:
return
"HIPROC"
;
case
SHT_LOUSER:
return
"LOUSER"
;
case
SHT_HIUSER:
return
"HIUSER"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
* getSectionFlagStr(Elf_Word flags) {
switch
(flags) {
case
SHF_ALLOC:
return
" A"
;
case
SHF_WRITE:
return
" W"
;
case
SHF_WRITE | SHF_ALLOC:
return
" WA"
;
case
SHF_EXECINSTR:
return
" X"
;
case
SHF_ALLOC | SHF_EXECINSTR:
return
" AX"
;
case
SHF_MASKPROC:
return
"MKP"
;
default
:
return
" "
;
}
}
void
printElfSectionHeader32(
const
Elf32_Shdr* pSectionHeader,Elf_Half sectionNum,
const
char
* pStringTable) {
printf
(
"ELF Section Headers:\n"
);
printf
(
"\t[Nr] Name\t\t\tType\t\t\tAddr\t\tOffset\t\tSize\t\tEntSize\tFlag\tLink\tInfo\tAlign\n"
);
for
(
int
i = 0; i < sectionNum; i++) {
printf
(
"\t[%2d] %-20s"
, i, (
char
*) &pStringTable[pSectionHeader[i].sh_name]);
printf
(
"\t%-16s"
, getSectionTypeString(pSectionHeader[i].sh_type));
printf
(
"\t%08x"
, pSectionHeader[i].sh_addr);
printf
(
"\t%08x"
, pSectionHeader[i].sh_offset);
printf
(
"\t%08x"
, pSectionHeader[i].sh_size);
printf
(
"\t%x"
, pSectionHeader[i].sh_entsize);
printf
(
"\t%s"
, getSectionFlagStr(pSectionHeader[i].sh_flags));
printf
(
"\t%x"
, pSectionHeader[i].sh_link);
printf
(
"\t%x"
, pSectionHeader[i].sh_info);
printf
(
"\t%x\n"
, pSectionHeader[i].sh_addralign);
}
printf
(
"ELF Section Headers End\n"
);
}
typedef
struct
{
Elf32_Word p_type;
/* Segment type */
Elf32_Off p_offset;
/* Segment file offset */
Elf32_Addr p_vaddr;
/* Segment virtual address */
Elf32_Addr p_paddr;
/* Segment physical address */
Elf32_Word p_filesz;
/* Segment size in file */
Elf32_Word p_memsz;
/* Segment size in memory */
Elf32_Word p_flags;
/* Segment flags */
Elf32_Word p_align;
/* Segment alignment */
} Elf32_Phdr;
typedef
struct
{
Elf64_Word p_type;
/* Segment type */
Elf64_Word p_flags;
/* Segment flags */
Elf64_Off p_offset;
/* Segment file offset */
Elf64_Addr p_vaddr;
/* Segment virtual address */
Elf64_Addr p_paddr;
/* Segment physical address */
Elf64_Xword p_filesz;
/* Segment size in file */
Elf64_Xword p_memsz;
/* Segment size in memory */
Elf64_Xword p_align;
/* Segment alignment */
} Elf64_Phdr;
typedef
struct
{
Elf32_Word p_type;
/* Segment type */
Elf32_Off p_offset;
/* Segment file offset */
Elf32_Addr p_vaddr;
/* Segment virtual address */
Elf32_Addr p_paddr;
/* Segment physical address */
Elf32_Word p_filesz;
/* Segment size in file */
Elf32_Word p_memsz;
/* Segment size in memory */
Elf32_Word p_flags;
/* Segment flags */
Elf32_Word p_align;
/* Segment alignment */
} Elf32_Phdr;
typedef
struct
{
Elf64_Word p_type;
/* Segment type */
Elf64_Word p_flags;
/* Segment flags */
Elf64_Off p_offset;
/* Segment file offset */
Elf64_Addr p_vaddr;
/* Segment virtual address */
Elf64_Addr p_paddr;
/* Segment physical address */
Elf64_Xword p_filesz;
/* Segment size in file */
Elf64_Xword p_memsz;
/* Segment size in memory */
Elf64_Xword p_align;
/* Segment alignment */
} Elf64_Phdr;
/* Legal values for p_type (segment type). */
#define PT_NULL 0 /* Program header table entry unused */
#define PT_LOAD 1 /* Loadable program segment */
#define PT_DYNAMIC 2 /* Dynamic linking information */
#define PT_INTERP 3 /* Program interpreter */
#define PT_NOTE 4 /* Auxiliary information */
#define PT_SHLIB 5 /* Reserved */
#define PT_PHDR 6 /* Entry for header table itself */
#define PT_TLS 7 /* Thread-local storage segment */
#define PT_NUM 8 /* Number of defined types */
#define PT_LOOS 0x60000000 /* Start of OS-specific */
#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
#define PT_GNU_PROPERTY 0x6474e553 /* GNU property */
#define PT_GNU_SFRAME 0x6474e554 /* SFrame segment. */
#define PT_LOSUNW 0x6ffffffa
#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
#define PT_HISUNW 0x6fffffff
#define PT_HIOS 0x6fffffff /* End of OS-specific */
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
#define PT_HIPROC 0x7fffffff /* End of processor-specific */
/* Legal values for p_type (segment type). */
#define PT_NULL 0 /* Program header table entry unused */
#define PT_LOAD 1 /* Loadable program segment */
#define PT_DYNAMIC 2 /* Dynamic linking information */
#define PT_INTERP 3 /* Program interpreter */
#define PT_NOTE 4 /* Auxiliary information */
#define PT_SHLIB 5 /* Reserved */
#define PT_PHDR 6 /* Entry for header table itself */
#define PT_TLS 7 /* Thread-local storage segment */
#define PT_NUM 8 /* Number of defined types */
#define PT_LOOS 0x60000000 /* Start of OS-specific */
#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
#define PT_GNU_PROPERTY 0x6474e553 /* GNU property */
#define PT_GNU_SFRAME 0x6474e554 /* SFrame segment. */
#define PT_LOSUNW 0x6ffffffa
#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
#define PT_HISUNW 0x6fffffff
#define PT_HIOS 0x6fffffff /* End of OS-specific */
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
#define PT_HIPROC 0x7fffffff /* End of processor-specific */
/* Legal values for p_flags (segment flags). */
#define PF_X (1 << 0) /* Segment is executable */ //可读
#define PF_W (1 << 1) /* Segment is writable */ //可写
#define PF_R (1 << 2) /* Segment is readable */ //可执行
#define PF_MASKOS 0x0ff00000 /* OS-specific */ //系统指定
#define PF_MASKPROC 0xf0000000 /* Processor-specific */ //进程指定
/* Legal values for p_flags (segment flags). */
#define PF_X (1 << 0) /* Segment is executable */ //可读
#define PF_W (1 << 1) /* Segment is writable */ //可写
#define PF_R (1 << 2) /* Segment is readable */ //可执行
#define PF_MASKOS 0x0ff00000 /* OS-specific */ //系统指定
#define PF_MASKPROC 0xf0000000 /* Processor-specific */ //进程指定
// Print ELF Program Headers
const
char
*getSegmentTypeStr(Elf32_Word segmentType) {
switch
(segmentType) {
case
PT_NULL:
return
"NULL"
;
case
PT_LOAD:
return
"LOAD"
;
case
PT_DYNAMIC:
return
"DYNAMIC"
;
case
PT_INTERP:
return
"INTERP"
;
case
PT_NOTE:
return
"NOTE"
;
case
PT_SHLIB:
return
"SHLIB"
;
case
PT_PHDR:
return
"PHDR"
;
case
PT_TLS:
return
"TLS"
;
case
PT_NUM:
return
"PT_NUM"
;
case
PT_LOOS:
return
"LOOS"
;
case
PT_GNU_EH_FRAME:
return
"GNU_EH_FRAME"
;
case
PT_GNU_STACK:
return
"GNU_STACK"
;
case
PT_GNU_RELRO:
return
"GNU_RELRO"
;
case
PT_GNU_PROPERTY:
return
"GNU_PROPERTY"
;
case
PT_GNU_SFRAME:
return
"GNU_SFRAME"
;
case
PT_SUNWBSS:
return
"SUNWBSS"
;
case
PT_SUNWSTACK:
return
"SUNWSTACK"
;
case
PT_HIOS:
return
"HIOS"
;
case
PT_LOPROC:
return
"LOPROC"
;
case
PT_HIPROC:
return
"HIPROC"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
* getSegmentFlagStr(Elf_Word segmentFlags) {
static
char
segmentFlagStr[5] =
" "
;
int
count = 0;
if
(segmentFlags & PF_R) {
segmentFlagStr[count++] =
'R'
;
}
if
(segmentFlags & PF_W) {
segmentFlagStr[count++] =
'W'
;
}
if
(segmentFlags & PF_X) {
segmentFlagStr[count++] =
'X'
;
}
return
segmentFlagStr;
}
void
printElfProgramHeader32(
const
Elf32_Phdr *pProgramHeader,Elf_Half segmentNum,
const
uint8_t* pFileBuffer) {
printf
(
"ELF ProgramHeader:\n"
);
printf
(
"\t[Nr] Type\t\tFileOff\t\tVirAddr\t\tPhyAddr\t\tFileSize\tMemSize\t\tFlag\tAlign\n"
);
for
(
int
i = 0; i < segmentNum; i++) {
printf
(
"\t[%02d] %-16s"
, i, getSegmentTypeStr(pProgramHeader[i].p_type));
printf
(
"\t%08x"
, pProgramHeader[i].p_offset);
printf
(
"\t%08x"
, pProgramHeader[i].p_vaddr);
printf
(
"\t%08x"
, pProgramHeader[i].p_paddr);
printf
(
"\t%08x"
, pProgramHeader[i].p_filesz);
printf
(
"\t%08x"
, pProgramHeader[i].p_memsz);
printf
(
"\t%#4s"
, getSegmentFlagStr(pProgramHeader[i].p_flags));
printf
(
"\t%#x\n"
, pProgramHeader[i].p_align);
if
(pProgramHeader[i].p_type == PT_INTERP) {
printf
(
"\t\t [Request Program Interpreter Path: %s]\n"
,(
char
*) (pFileBuffer + pProgramHeader[i].p_offset));
}
}
printf
(
"ELF ProgramHeader End\n"
);
}
// print segment mapping
void
printSectionToSegmentMapping32(
const
Elf32_Phdr* pProgramHeader,
const
Elf32_Shdr* pSectionHeader,Elf_Half segmentNum,Elf_Half sectionNum,
const
char
* pSectionHeaderStringTable) {
printf
(
"Segtion to Segment Mapping:\n"
);
printf
(
"\tSegment\tSections\n"
);
//Traverse program headers
for
(
int
i = 0; i < segmentNum; i++) {
Elf32_Addr segmentStartAddr = pProgramHeader[i].p_vaddr;
Elf32_Addr segmentEndAddr = segmentStartAddr + pProgramHeader[i].p_memsz;
printf
(
"\t%02d\t\t"
, i);
//Traverse section headers
for
(
int
j = 0; j < sectionNum; j++) {
Elf32_Addr sectionStartAddr = pSectionHeader[j].sh_addr;
//Check whether the start addr of a section is in the segment addr
if
(sectionStartAddr >= segmentStartAddr && sectionStartAddr < segmentEndAddr) {
//SHF_ALLOC means need alloc memory, some control sections don't need mapping to memory
if
(pSectionHeader[j].sh_flags & SHF_ALLOC) {
printf
(
"%s "
,(
char
*) pSectionHeaderStringTable + pSectionHeader[j].sh_name);
}
}
}
printf
(
"\n"
);
}
}
// Print ELF Program Headers
const
char
*getSegmentTypeStr(Elf32_Word segmentType) {
switch
(segmentType) {
case
PT_NULL:
return
"NULL"
;
case
PT_LOAD:
return
"LOAD"
;
case
PT_DYNAMIC:
return
"DYNAMIC"
;
case
PT_INTERP:
return
"INTERP"
;
case
PT_NOTE:
return
"NOTE"
;
case
PT_SHLIB:
return
"SHLIB"
;
case
PT_PHDR:
return
"PHDR"
;
case
PT_TLS:
return
"TLS"
;
case
PT_NUM:
return
"PT_NUM"
;
case
PT_LOOS:
return
"LOOS"
;
case
PT_GNU_EH_FRAME:
return
"GNU_EH_FRAME"
;
case
PT_GNU_STACK:
return
"GNU_STACK"
;
case
PT_GNU_RELRO:
return
"GNU_RELRO"
;
case
PT_GNU_PROPERTY:
return
"GNU_PROPERTY"
;
case
PT_GNU_SFRAME:
return
"GNU_SFRAME"
;
case
PT_SUNWBSS:
return
"SUNWBSS"
;
case
PT_SUNWSTACK:
return
"SUNWSTACK"
;
case
PT_HIOS:
return
"HIOS"
;
case
PT_LOPROC:
return
"LOPROC"
;
case
PT_HIPROC:
return
"HIPROC"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
* getSegmentFlagStr(Elf_Word segmentFlags) {
static
char
segmentFlagStr[5] =
" "
;
int
count = 0;
if
(segmentFlags & PF_R) {
segmentFlagStr[count++] =
'R'
;
}
if
(segmentFlags & PF_W) {
segmentFlagStr[count++] =
'W'
;
}
if
(segmentFlags & PF_X) {
segmentFlagStr[count++] =
'X'
;
}
return
segmentFlagStr;
}
void
printElfProgramHeader32(
const
Elf32_Phdr *pProgramHeader,Elf_Half segmentNum,
const
uint8_t* pFileBuffer) {
printf
(
"ELF ProgramHeader:\n"
);
printf
(
"\t[Nr] Type\t\tFileOff\t\tVirAddr\t\tPhyAddr\t\tFileSize\tMemSize\t\tFlag\tAlign\n"
);
for
(
int
i = 0; i < segmentNum; i++) {
printf
(
"\t[%02d] %-16s"
, i, getSegmentTypeStr(pProgramHeader[i].p_type));
printf
(
"\t%08x"
, pProgramHeader[i].p_offset);
printf
(
"\t%08x"
, pProgramHeader[i].p_vaddr);
printf
(
"\t%08x"
, pProgramHeader[i].p_paddr);
printf
(
"\t%08x"
, pProgramHeader[i].p_filesz);
printf
(
"\t%08x"
, pProgramHeader[i].p_memsz);
printf
(
"\t%#4s"
, getSegmentFlagStr(pProgramHeader[i].p_flags));
printf
(
"\t%#x\n"
, pProgramHeader[i].p_align);
if
(pProgramHeader[i].p_type == PT_INTERP) {
printf
(
"\t\t [Request Program Interpreter Path: %s]\n"
,(
char
*) (pFileBuffer + pProgramHeader[i].p_offset));
}
}
printf
(
"ELF ProgramHeader End\n"
);
}
// print segment mapping
void
printSectionToSegmentMapping32(
const
Elf32_Phdr* pProgramHeader,
const
Elf32_Shdr* pSectionHeader,Elf_Half segmentNum,Elf_Half sectionNum,
const
char
* pSectionHeaderStringTable) {
printf
(
"Segtion to Segment Mapping:\n"
);
printf
(
"\tSegment\tSections\n"
);
//Traverse program headers
for
(
int
i = 0; i < segmentNum; i++) {
Elf32_Addr segmentStartAddr = pProgramHeader[i].p_vaddr;
Elf32_Addr segmentEndAddr = segmentStartAddr + pProgramHeader[i].p_memsz;
printf
(
"\t%02d\t\t"
, i);
//Traverse section headers
for
(
int
j = 0; j < sectionNum; j++) {
Elf32_Addr sectionStartAddr = pSectionHeader[j].sh_addr;
//Check whether the start addr of a section is in the segment addr
if
(sectionStartAddr >= segmentStartAddr && sectionStartAddr < segmentEndAddr) {
//SHF_ALLOC means need alloc memory, some control sections don't need mapping to memory
if
(pSectionHeader[j].sh_flags & SHF_ALLOC) {
printf
(
"%s "
,(
char
*) pSectionHeaderStringTable + pSectionHeader[j].sh_name);
}
}
}
printf
(
"\n"
);
}
}
节名 | 作用 |
---|---|
.text | 代码段 |
.data | 保存已经初始化的全局变量和局部静态变量 |
.bss | 保存未初始化的全局变量和局部静态变量 |
.rodata | 存放只读数据, 例如常量字符串 |
.comment | 编译器版本信息 |
.debug | 调试信息 |
.dynamic | 动态链接信息, linker解析该段以加载elf文件 |
.hash | 符号哈希表 (可查导入和导出符号) |
.gnu.hash | GNU哈希表 (只可查导出符号,导出表) |
.line | 调试行号表 即源代码行号与编译后指令的对应表 |
.note | 额外的编译器信息 例如公司名,版本号 |
.rel.dyn | 动态链接重定位表 存放全局变量重定位项 |
.rel.plt | 动态链接函数跳转重定位表 存放plt重定位项 |
.symtab | 符号表 |
.dynsym | 动态链接符号表 |
.strtab | 字符串表 |
.shstrtab | 节名表 |
.dynstr | 动态链接字符串表 |
.plt | 动态链接跳转表 |
.got | 动态链接全局偏移表 |
.init | 程序初始化代码段(节) |
.fini | 程序结束代码段(节) |
// Print String Table
void
printStringTable32(
const
Elf32_Shdr* pSectionHeader,Elf_Half sectionNum,
const
char
* pSectionHeaderStringTable,
const
uint8_t* pFileBuffer) {
//Traverse the section header table then find string table
printf
(
"ELF String Table:\n"
);
for
(
int
i = 0; i < sectionNum; i++) {
//not only just one string table such as .dynstr .strtab
if
(pSectionHeader[i].sh_type == SHT_STRTAB) {
printf
(
"\t==========String Table %s==========\n"
,getSectionName(pSectionHeaderStringTable,pSectionHeader[i].sh_name));
char
*pStringTable = (
char
*) (pFileBuffer + pSectionHeader[i].sh_offset);
Elf32_Word stringTableSize = pSectionHeader[i].sh_size, pos = 0;
//遍历字符串表, 遇到0时pos+1打印字符串, 非0时继续搜索
while
(pos < stringTableSize) {
if
(pStringTable[pos] == 0) {
pos += 1;
printf
(
"\t%s\n"
, pStringTable + pos);
}
else
{
//find zero
while
(pStringTable[pos] != 0) {
pos++;
}
}
}
}
}
printf
(
"ELF String Table End\n"
);
}
// Print String Table
void
printStringTable32(
const
Elf32_Shdr* pSectionHeader,Elf_Half sectionNum,
const
char
* pSectionHeaderStringTable,
const
uint8_t* pFileBuffer) {
//Traverse the section header table then find string table
printf
(
"ELF String Table:\n"
);
for
(
int
i = 0; i < sectionNum; i++) {
//not only just one string table such as .dynstr .strtab
if
(pSectionHeader[i].sh_type == SHT_STRTAB) {
printf
(
"\t==========String Table %s==========\n"
,getSectionName(pSectionHeaderStringTable,pSectionHeader[i].sh_name));
char
*pStringTable = (
char
*) (pFileBuffer + pSectionHeader[i].sh_offset);
Elf32_Word stringTableSize = pSectionHeader[i].sh_size, pos = 0;
//遍历字符串表, 遇到0时pos+1打印字符串, 非0时继续搜索
while
(pos < stringTableSize) {
if
(pStringTable[pos] == 0) {
pos += 1;
printf
(
"\t%s\n"
, pStringTable + pos);
}
else
{
//find zero
while
(pStringTable[pos] != 0) {
pos++;
}
}
}
}
}
printf
(
"ELF String Table End\n"
);
}
.dynsym
//动态链接符号表
.symtab
//符号表
.dynstr
//动态链接符号表的字符串表
.strtab
//符号表的字符串表
.dynsym
//动态链接符号表
.symtab
//符号表
.dynstr
//动态链接符号表的字符串表
.strtab
//符号表的字符串表
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 */
Elf32_Section st_shndx;
/* Section index */
} Elf32_Sym;
typedef
struct
{
Elf64_Word st_name;
/* Symbol name (string tbl index) */
unsigned
char
st_info;
/* Symbol type and binding */
unsigned
char
st_other;
/* Symbol visibility */
Elf64_Section st_shndx;
/* Section index */
Elf64_Addr st_value;
/* Symbol value */
Elf64_Xword st_size;
/* Symbol size */
} Elf64_Sym;
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 */
Elf32_Section st_shndx;
/* Section index */
} Elf32_Sym;
typedef
struct
{
Elf64_Word st_name;
/* Symbol name (string tbl index) */
unsigned
char
st_info;
/* Symbol type and binding */
unsigned
char
st_other;
/* Symbol visibility */
Elf64_Section st_shndx;
/* Section index */
Elf64_Addr st_value;
/* Symbol value */
Elf64_Xword st_size;
/* Symbol size */
} Elf64_Sym;
/* How to extract and insert information held in the st_info field. */
#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
#define ELF32_ST_TYPE(val) ((val) & 0xf)
#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
/* How to extract and insert information held in the st_info field. */
#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
#define ELF32_ST_TYPE(val) ((val) & 0xf)
#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
/* Legal values for ST_BIND subfield of st_info (symbol binding). */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* Weak symbol */
#define STB_NUM 3 /* Number of defined types. */
#define STB_LOOS 10 /* Start of OS-specific */
#define STB_GNU_UNIQUE 10 /* Unique symbol. */
#define STB_HIOS 12 /* End of OS-specific */
#define STB_LOPROC 13 /* Start of processor-specific */
#define STB_HIPROC 15 /* End of processor-specific */
/* Legal values for ST_BIND subfield of st_info (symbol binding). */
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
#define STB_WEAK 2 /* Weak symbol */
#define STB_NUM 3 /* Number of defined types. */
#define STB_LOOS 10 /* Start of OS-specific */
#define STB_GNU_UNIQUE 10 /* Unique symbol. */
#define STB_HIOS 12 /* End of OS-specific */
#define STB_LOPROC 13 /* Start of processor-specific */
#define STB_HIPROC 15 /* End of processor-specific */
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
#define STT_NOTYPE 0 /* Symbol type is unspecified */
#define STT_OBJECT 1 /* Symbol is a data object */
#define STT_FUNC 2 /* Symbol is a code object */
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Symbol's name is file name */
#define STT_COMMON 5 /* Symbol is a common data object */
#define STT_TLS 6 /* Symbol is thread-local data object*/
#define STT_NUM 7 /* Number of defined types. */
#define STT_LOOS 10 /* Start of OS-specific */
#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
#define STT_HIOS 12 /* End of OS-specific */
#define STT_LOPROC 13 /* Start of processor-specific */
#define STT_HIPROC 15 /* End of processor-specific */
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
#define STT_NOTYPE 0 /* Symbol type is unspecified */
#define STT_OBJECT 1 /* Symbol is a data object */
#define STT_FUNC 2 /* Symbol is a code object */
#define STT_SECTION 3 /* Symbol associated with a section */
#define STT_FILE 4 /* Symbol's name is file name */
#define STT_COMMON 5 /* Symbol is a common data object */
#define STT_TLS 6 /* Symbol is thread-local data object*/
#define STT_NUM 7 /* Number of defined types. */
#define STT_LOOS 10 /* Start of OS-specific */
#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
#define STT_HIOS 12 /* End of OS-specific */
#define STT_LOPROC 13 /* Start of processor-specific */
#define STT_HIPROC 15 /* End of processor-specific */
// Print Symbol Table
const
char
*getSymbolBindingString(uint8_t symbolBinding) {
switch
(symbolBinding) {
case
STB_LOCAL:
return
"LOCAL"
;
case
STB_GLOBAL:
return
"GLOBAL"
;
case
STB_WEAK:
return
"WEAK"
;
case
STB_NUM:
return
"STB_NUM"
;
case
STB_GNU_UNIQUE:
return
"GNU_UNIQUE"
;
case
STB_HIOS:
return
"STB_HIOS"
;
case
STB_LOPROC:
return
"STB_LOPROC"
;
case
STB_HIPROC:
return
"STB_HIPROC"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
*getSymbolTypeString(uint8_t symbolType) {
switch
(symbolType) {
case
STT_NOTYPE:
return
"NOTYPE"
;
case
STT_OBJECT:
return
"OBJECT"
;
case
STT_FUNC:
return
"FUNC"
;
case
STT_SECTION:
return
"SECTION"
;
case
STT_FILE:
return
"FILE"
;
case
STT_COMMON:
return
"COMMON"
;
case
STT_TLS:
return
"TLS"
;
case
STT_NUM:
return
"STT_NUM"
;
case
STT_GNU_IFUNC:
return
"GNU_IFUNC"
;
case
STT_HIOS:
return
"HIOS"
;
case
STT_LOPROC:
return
"LOPROC"
;
case
STT_HIPROC:
return
"HIPROC"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
*getSymbolVisibility(uint8_t st_other) {
unsigned
char
visibility = st_other & 0x03;
switch
(visibility) {
case
0:
return
"DEFAULT"
;
case
1:
return
"INTERNAL"
;
case
2:
return
"HIDDEN"
;
case
3:
return
"PROTECTED"
;
default
:
return
"UNKNOWN"
;
}
}
void
printSymbolTable32(
const
Elf32_Shdr* pSectionHeader,Elf_Half sectionNum,
const
char
* pSectionHeaderStringTable,
const
uint8_t* pFileBuffer) {
printf
(
"ELF Symbol Tables:\n"
);
for
(
int
i = 0; i < sectionNum; i++) {
//全局静态符号表和动态符号表
if
(pSectionHeader[i].sh_type == SHT_SYMTAB || pSectionHeader[i].sh_type == SHT_DYNSYM) {
Elf32_Word symbolNum = pSectionHeader[i].sh_size / pSectionHeader[i].sh_entsize;
//获取符号表对应的字符串表,全局静态符号和动态符号表对应字符串表可能不同 sh_link is index of string table, fileBuffer+offset is real string table
char
* pSymbolNameTable =(
char
*) pFileBuffer + pSectionHeader[pSectionHeader[i].sh_link].sh_offset;
printf
(
"\tSymbol Table '%s' contains %#x entries:\n"
,(
char
*)getSectionName(pSectionHeaderStringTable,pSectionHeader[i].sh_name), symbolNum);
printf
(
"\tNum \tValue\t\tSize\t\tType\t\tBind\t\tVisible\t\tIndex\t\tName\n"
);
Elf32_Sym *pSymbolTable = (Elf32_Sym *) (pFileBuffer + pSectionHeader[i].sh_offset);
for
(
int
j = 0; j < symbolNum; j++) {
printf
(
"\t%04d"
, j);
printf
(
"\t%08x"
, pSymbolTable[j].st_value);
printf
(
"\t%08x"
, pSymbolTable[j].st_size);
//symbol type and binding
printf
(
"\t%s\t"
, getSymbolTypeString(ELF32_ST_TYPE(pSymbolTable[j].st_info)));
printf
(
"\t%s\t"
, getSymbolBindingString(ELF32_ST_BIND(pSymbolTable[j].st_info)));
printf
(
"\t%-10s"
, getSymbolVisibility(pSymbolTable[j].st_other));
if
(pSymbolTable[j].st_shndx == SHN_UNDEF) {
printf
(
"\t%4s\t"
,
"UDEF"
);
}
else
if
(pSymbolTable[j].st_shndx == SHN_ABS) {
printf
(
"\t%4s\t"
,
"ABS"
);
}
else
{
printf
(
"\t%04x\t"
, pSymbolTable[j].st_shndx);
}
printf
(
"\t%s\n"
, pSymbolNameTable + pSymbolTable[j].st_name);
}
printf
(
"\n"
);
}
}
}
// Print Symbol Table
const
char
*getSymbolBindingString(uint8_t symbolBinding) {
switch
(symbolBinding) {
case
STB_LOCAL:
return
"LOCAL"
;
case
STB_GLOBAL:
return
"GLOBAL"
;
case
STB_WEAK:
return
"WEAK"
;
case
STB_NUM:
return
"STB_NUM"
;
case
STB_GNU_UNIQUE:
return
"GNU_UNIQUE"
;
case
STB_HIOS:
return
"STB_HIOS"
;
case
STB_LOPROC:
return
"STB_LOPROC"
;
case
STB_HIPROC:
return
"STB_HIPROC"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
*getSymbolTypeString(uint8_t symbolType) {
switch
(symbolType) {
case
STT_NOTYPE:
return
"NOTYPE"
;
case
STT_OBJECT:
return
"OBJECT"
;
case
STT_FUNC:
return
"FUNC"
;
case
STT_SECTION:
return
"SECTION"
;
case
STT_FILE:
return
"FILE"
;
case
STT_COMMON:
return
"COMMON"
;
case
STT_TLS:
return
"TLS"
;
case
STT_NUM:
return
"STT_NUM"
;
case
STT_GNU_IFUNC:
return
"GNU_IFUNC"
;
case
STT_HIOS:
return
"HIOS"
;
case
STT_LOPROC:
return
"LOPROC"
;
case
STT_HIPROC:
return
"HIPROC"
;
default
:
return
"UNKNOWN"
;
}
}
const
char
*getSymbolVisibility(uint8_t st_other) {
unsigned
char
visibility = st_other & 0x03;
switch
(visibility) {
case
0:
return
"DEFAULT"
;
case
1:
return
"INTERNAL"
;
case
2:
return
"HIDDEN"
;
case
3:
return
"PROTECTED"
;
default
:
return
"UNKNOWN"
;
}
}
void
printSymbolTable32(
const
Elf32_Shdr* pSectionHeader,Elf_Half sectionNum,
const
char
* pSectionHeaderStringTable,
const
uint8_t* pFileBuffer) {
printf
(
"ELF Symbol Tables:\n"
);
for
(
int
i = 0; i < sectionNum; i++) {
//全局静态符号表和动态符号表
if
(pSectionHeader[i].sh_type == SHT_SYMTAB || pSectionHeader[i].sh_type == SHT_DYNSYM) {
Elf32_Word symbolNum = pSectionHeader[i].sh_size / pSectionHeader[i].sh_entsize;
//获取符号表对应的字符串表,全局静态符号和动态符号表对应字符串表可能不同 sh_link is index of string table, fileBuffer+offset is real string table
char
* pSymbolNameTable =(
char
*) pFileBuffer + pSectionHeader[pSectionHeader[i].sh_link].sh_offset;
printf
(
"\tSymbol Table '%s' contains %#x entries:\n"
,(
char
*)getSectionName(pSectionHeaderStringTable,pSectionHeader[i].sh_name), symbolNum);
printf
(
"\tNum \tValue\t\tSize\t\tType\t\tBind\t\tVisible\t\tIndex\t\tName\n"
);
Elf32_Sym *pSymbolTable = (Elf32_Sym *) (pFileBuffer + pSectionHeader[i].sh_offset);
for
(
int
j = 0; j < symbolNum; j++) {
printf
(
"\t%04d"
, j);
printf
(
"\t%08x"
, pSymbolTable[j].st_value);
printf
(
"\t%08x"
, pSymbolTable[j].st_size);
//symbol type and binding
printf
(
"\t%s\t"
, getSymbolTypeString(ELF32_ST_TYPE(pSymbolTable[j].st_info)));
printf
(
"\t%s\t"
, getSymbolBindingString(ELF32_ST_BIND(pSymbolTable[j].st_info)));
printf
(
"\t%-10s"
, getSymbolVisibility(pSymbolTable[j].st_other));
if
(pSymbolTable[j].st_shndx == SHN_UNDEF) {
printf
(
"\t%4s\t"
,
"UDEF"
);
}
else
if
(pSymbolTable[j].st_shndx == SHN_ABS) {
printf
(
"\t%4s\t"
,
"ABS"
);
}
else
{
printf
(
"\t%04x\t"
, pSymbolTable[j].st_shndx);
}
printf
(
"\t%s\n"
, pSymbolNameTable + pSymbolTable[j].st_name);
}
printf
(
"\n"
);
}
}
}
/* Relocation table entry without addend (in section of type SHT_REL). */
typedef
struct
{
Elf32_Addr r_offset;
/* Address */
Elf32_Word r_info;
/* Relocation type and symbol index */
} Elf32_Rel;
typedef
struct
{
Elf64_Addr r_offset;
/* Address */
Elf64_Xword r_info;
/* Relocation type and symbol index */
} Elf64_Rel;
/* Relocation table entry with addend (in section of type SHT_RELA). */
typedef
struct
{
Elf32_Addr r_offset;
/* Address */
Elf32_Word r_info;
/* Relocation type and symbol index */
Elf32_Sword r_addend;
/* Addend */
} Elf32_Rela;
typedef
struct
{
Elf64_Addr r_offset;
/* Address */
Elf64_Xword r_info;
/* Relocation type and symbol index */
Elf64_Sxword r_addend;
/* Addend */
} Elf64_Rela;
/* RELR relocation table entry */
typedef
Elf32_Word Elf32_Relr;
typedef
Elf64_Xword Elf64_Relr;
/* Relocation table entry without addend (in section of type SHT_REL). */
typedef
struct
{
Elf32_Addr r_offset;
/* Address */
Elf32_Word r_info;
/* Relocation type and symbol index */
} Elf32_Rel;
typedef
struct
{
Elf64_Addr r_offset;
/* Address */
Elf64_Xword r_info;
/* Relocation type and symbol index */
} Elf64_Rel;
/* Relocation table entry with addend (in section of type SHT_RELA). */
typedef
struct
{
Elf32_Addr r_offset;
/* Address */
Elf32_Word r_info;
/* Relocation type and symbol index */
Elf32_Sword r_addend;
/* Addend */
} Elf32_Rela;
typedef
struct
{
Elf64_Addr r_offset;
/* Address */
Elf64_Xword r_info;
/* Relocation type and symbol index */
Elf64_Sxword r_addend;
/* Addend */
} Elf64_Rela;
/* RELR relocation table entry */
typedef
Elf32_Word Elf32_Relr;
typedef
Elf64_Xword Elf64_Relr;
/* How to extract and insert information held in the r_info field. */
#define ELF32_R_SYM(val) ((val) >> 8)
#define ELF32_R_TYPE(val) ((val) & 0xff)
#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
/* How to extract and insert information held in the r_info field. */
#define ELF32_R_SYM(val) ((val) >> 8)
#define ELF32_R_TYPE(val) ((val) & 0xff)
#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
/* Intel 80386 specific definitions. */
/* i386 relocs. */
#define R_386_NONE 0 /* No reloc */
#define R_386_32 1 /* Direct 32 bit */
#define R_386_PC32 2 /* PC relative 32 bit */
#define R_386_GOT32 3 /* 32 bit GOT entry */
#define R_386_PLT32 4 /* 32 bit PLT address */
#define R_386_COPY 5 /* Copy symbol at runtime */
#define R_386_GLOB_DAT 6 /* Create GOT entry */
#define R_386_JMP_SLOT 7 /* Create PLT entry */
#define R_386_RELATIVE 8 /* Adjust by program base */
#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
#define R_386_32PLT 11
#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
block offset */
#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
offset */
#define R_386_TLS_LE 17 /* Offset relative to static TLS
block */
#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
general dynamic
thread
local data */
#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
local dynamic
thread
local data
in LE code */
#define R_386_16 20
#define R_386_PC16 21
#define R_386_8 22
#define R_386_PC8 23
#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
thread
local data */
#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
#define R_386_TLS_GD_CALL 26 /* Relocation for call to
__tls_get_addr() */
#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
thread
local data in LE code */
#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
__tls_get_addr() in LDM code */
#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
block offset */
#define R_386_TLS_LE_32 34 /* Negated offset relative to static
TLS block */
#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
#define R_386_SIZE32 38 /* 32-bit symbol size */
#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */
#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS
descriptor
for
relaxation. */
#define R_386_TLS_DESC 41 /* TLS descriptor containing
pointer to code and to
argument, returning the TLS
offset
for
the symbol. */
#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
#define R_386_GOT32X 43 /* Load from 32 bit GOT entry,
relaxable. */
/* Keep this the last entry. */
#define R_386_NUM 44
/* Intel 80386 specific definitions. */
/* i386 relocs. */
#define R_386_NONE 0 /* No reloc */
#define R_386_32 1 /* Direct 32 bit */
#define R_386_PC32 2 /* PC relative 32 bit */
#define R_386_GOT32 3 /* 32 bit GOT entry */
#define R_386_PLT32 4 /* 32 bit PLT address */
#define R_386_COPY 5 /* Copy symbol at runtime */
#define R_386_GLOB_DAT 6 /* Create GOT entry */
#define R_386_JMP_SLOT 7 /* Create PLT entry */
#define R_386_RELATIVE 8 /* Adjust by program base */
#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
#define R_386_32PLT 11
#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
block offset */
#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
offset */
#define R_386_TLS_LE 17 /* Offset relative to static TLS
block */
#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
general dynamic
thread
local data */
#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
local dynamic
thread
local data
in LE code */
#define R_386_16 20
#define R_386_PC16 21
#define R_386_8 22
#define R_386_PC8 23
#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
thread
local data */
#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
#define R_386_TLS_GD_CALL 26 /* Relocation for call to
__tls_get_addr() */
#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
thread
local data in LE code */
#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
__tls_get_addr() in LDM code */
#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
block offset */
#define R_386_TLS_LE_32 34 /* Negated offset relative to static
TLS block */
#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
#define R_386_SIZE32 38 /* 32-bit symbol size */
#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */
#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS
descriptor
for
relaxation. */
#define R_386_TLS_DESC 41 /* TLS descriptor containing
pointer to code and to
argument, returning the TLS
offset
for
the symbol. */
#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
#define R_386_GOT32X 43 /* Load from 32 bit GOT entry,
relaxable. */
/* Keep this the last entry. */
#define R_386_NUM 44
/
*
AMD x86
-
64
relocations.
*
/
#define R_X86_64_NONE 0 /* No reloc */
#define R_X86_64_64 1 /* Direct 64 bit */
#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
#define R_X86_64_PLT32 4 /* 32 bit PLT address */
#define R_X86_64_COPY 5 /* Copy symbol at runtime */
#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
#define R_X86_64_RELATIVE 8 /* Adjust by program base */
#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
offset to GOT
*
/
#define R_X86_64_32 10 /* Direct 32 bit zero extended */
#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
#define R_X86_64_16 12 /* Direct 16 bit zero extended */
#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
#define R_X86_64_8 14 /* Direct 8 bit sign extended */
#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
to two GOT entries
for
GD symbol
*
/
#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
to two GOT entries
for
LD symbol
*
/
#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
to GOT entry
for
IE symbol
*
/
#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
#define R_X86_64_PC64 24 /* PC relative 64 bit */
#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */
#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative
offset to GOT
*
/
#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */
#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset
to GOT entry
*
/
#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */
#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */
#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset
to PLT entry
*
/
#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */
#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */
#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */
#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
descriptor.
*
/
#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */
/
*
39
Reserved was R_X86_64_PC32_BND
*
/
/
*
40
Reserved was R_X86_64_PLT32_BND
*
/
#define R_X86_64_GOTPCRELX 41 /* Load from 32 bit signed pc relative
offset to GOT entry without REX
prefix, relaxable.
*
/
#define R_X86_64_REX_GOTPCRELX 42 /* Load from 32 bit signed pc relative
offset to GOT entry with REX prefix,
relaxable.
*
/
#define R_X86_64_NUM 43
/
*
AMD x86
-
64
relocations.
*
/
#define R_X86_64_NONE 0 /* No reloc */
#define R_X86_64_64 1 /* Direct 64 bit */
#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
#define R_X86_64_PLT32 4 /* 32 bit PLT address */
#define R_X86_64_COPY 5 /* Copy symbol at runtime */
#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!