ELF文件&ELF-miner初识
ELF初识
ELF的全称是Executable and Linking Format,这个名字相当关键,包含了ELF所需要支持的两个功能——执行和链接。不管是ELF,还是Windows的PE
,抑或是MacOS的Mach-O
,其根本目的都是为了能让处理器正确执行我们所编写的代码。
- ELF Header是文件头,包含了固定长度的文件信息;
- Section Header Table则包含了链接时所需要用到的信息;
- Program Header Table中包含了运行时加载程序所需要的信息
Segment是指在程序运行时加载到内存的具有相同属性的区域,由一个或多个Section组成,比如有两个Section都要求加载到内存后可读可写,就属于同一个Segment。有些Section只对汇编器和链接器有意义,在运行时用不到,也不需要加载到内存,那么就不属于任何Segment。
注意Section Header Table和Program Header Table并不是一定要位于文件开头和结尾的,其位置由ELF Header指出,上图这么画只是为了清晰。
目标文件需要链接器做进一步处理,所以一定有Section Header Table;可执行文件需要加载运行,所以一定有Program Header Table;而共享库既要加载运行,又要在加载时做动态链接,所以既有Section Header Table又有Program Header Table。
ELF-Miner解析
ELF-Miner: Using Structural Knowledge and Data Mining Methods To Detect New (Linux) Malicious Executables
ELF Header
使用 readelf -h
读取ELF 头信息
typedef struct elf32_hdr
{
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;
文中使用除了offset之外的特征。
offset应该也可以作为特征。
Section Header
通过 readelf -S
读取sections' header
typedef struct elf32_shdr{
Elf32_Word sh_name; //节区名,名字是一个 NULL 结尾的字符串。
Elf32_Word sh_type; //为节区类型
Elf32_Word sh_flags; //节区标志
Elf32_Addr sh_addr; //节区的第一个字节应处的位置。否则,此字段为 0。
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;
Program header
用来保存程序加载到内存中所需要的信息,使用段(segment)来表示
通过 readelf -l
读取ELF程序头信息
typedef struct elf32_phdr{
Elf32_Word p_type; /* Magic number and other info */
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;
section
系统预订节区的,一般以点开头号,下面介绍下常见和比较重要的section
sh_name | sh_type | description |
---|---|---|
.text | SHT_PROGBITS | 代码段,包含程序的可执行指令。可以通过objdump -d 反汇编,查看ELF文件代码段内容。 |
.data | SHT_PROGBITS | 包含初始化了的数据,将出现在程序的内存映像中 |
.bss | SHT_NOBITS | 未初始化数据,因为只有符号所以 |
.rodata | SHT_PROGBITS | 包含只读数据 |
.comment | SHT_PROGBITS | 包含版本控制信息 |
.eh_frame | SHT_PROGBITS | 它生成描述如何unwind 堆栈的表 |
.debug | SHT_PROGBITS | 此节区包含用于符号调试的信息 |
.dynsym | SHT_DYNSYM | 此节区包含了动态链接符号表 |
.shstrtab | SHT_STRTAB | 存放section名,字符串表。Section Header String Table ELF所有的字符串集中放到一个表里,每一个字符串以’\0’分隔,然后使用字符串在表中的偏移来引用字符串。readelf -S xxx.o |
.strtab | SHT_STRTAB | 字符串表 |
.symtab | SHT_SYMTAB | 符号表 |
.got | SHT_PROGBITS | 全局偏移表 |
.plt | SHT_PROGBITS | 过程链接表 |
.relname | SHT_REL | 包含了重定位信息,例如 .text 节区的重定位节区名字将是:.rel.text |
… |
.dynsym 动态符号表
.symtab 静态符号表
在链接过程中,我们将函数和变量统称为符号,函数名和变量名就是符号名。
每个定义的符号都有一个相应的值,叫做符号值(Symbol Value),对于变量和函数,符号值就是它们的地址。
使用下面命令查看:readelf -s xxx.o
程序加载
Linux中分为用户态和内核态,执行ELF文件在用户态的表现就是执行execve系统调用,随后陷入内核进行处理。
references
http://www.genetic-programming.org/hc2011/05-Farooq/Farooq-Paper.pdf
https://github.com/shreyansh26/ELF-Miner
https://zhuanlan.zhihu.com/p/286088470