ELF文件&ELF-miner初识

ELF初识

ELF的全称是Executable and Linking Format,这个名字相当关键,包含了ELF所需要支持的两个功能——执行和链接。不管是ELF,还是Windows的PE,抑或是MacOS的Mach-O,其根本目的都是为了能让处理器正确执行我们所编写的代码。

image-20220125140206915

  • ELF Header是文件头,包含了固定长度的文件信息;
  • Section Header Table则包含了链接时所需要用到的信息;
  • Program Header Table中包含了运行时加载程序所需要的信息

Segment是指在程序运行时加载到内存的具有相同属性的区域,由一个或多个Section组成,比如有两个Section都要求加载到内存后可读可写,就属于同一个Segment。有些Section只对汇编器和链接器有意义,在运行时用不到,也不需要加载到内存,那么就不属于任何Segment。

img

注意Section Header Table和Program Header Table并不是一定要位于文件开头和结尾的,其位置由ELF Header指出,上图这么画只是为了清晰。

目标文件需要链接器做进一步处理,所以一定有Section Header Table;可执行文件需要加载运行,所以一定有Program Header Table;而共享库既要加载运行,又要在加载时做动态链接,所以既有Section Header Table又有Program Header Table。

img

ELF-Miner解析

ELF-Miner: Using Structural Knowledge and Data Mining Methods To Detect New (Linux) Malicious Executables

image-20220112161705284

ELF Header

使用 readelf -h读取ELF 头信息

image-20220125113754694

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

image-20220210174949337

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程序头信息

image-20220125112332816

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系统调用,随后陷入内核进行处理。

img

references

http://www.genetic-programming.org/hc2011/05-Farooq/Farooq-Paper.pdf

https://github.com/shreyansh26/ELF-Miner

https://zhuanlan.zhihu.com/p/286088470

https://paper.seebug.org/1289/

https://blog.csdn.net/daide2012/article/details/73065204

posted @ 2022-02-10 20:03  鱼与鱼  阅读(227)  评论(0编辑  收藏  举报