elf文件解析(1)——-文件头/段内容解析

  • Post author:
  • Post category:其他




ELF文件解析-文件头/段内容解析

ELF: 可执行连接格式

可执行连接格式是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface(ABI)而开发和发布的。工具接口标准委员会(TIS)选择了正在发展中的ELF标准作为工作在32位INTEL体系上不同操作系统之间可移植的二进制文件格式。

假定开发者定义了一个二进制接口集合,ELF标准用它来支持流线型的软件发展。应该减少不同执行接口的数量。因此可以减少重新编程重新编译的代码。



ELF Header

 #define EI_NIDENT       16
  typedef struct {
      unsigned char       e_ident[EI_NIDENT];
      Elf32_Half          e_type;
      Elf32_Half          e_machine;
      Elf32_Word          e_version;
      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;

示例:

在这里插入图片描述

EI_MAG0 to EI_MAG3(Magic的前四位):

​ 保存着魔术字,用于确定该文件是否为ELF的目标文件。

	Name       Value  Position
	====       =====  ========
 	ELFMAG0    0x7f   e_ident[EI_MAG0]
    	ELFMAG1    'E'    e_ident[EI_MAG1]
    	ELFMAG2    'L'    e_ident[EI_MAG2]
    	ELFMAG3    'F'    e_ident[EI_MAG3]

EI_CLASS(Class):

​ 说明文件的类型。

	Name           Value  Meaning
	====           =====  =======
	ELFCLASSNONE       0  Invalid class
	ELFCLASS32         1  32-bit objects
	ELFCLASS64         2  64-bit objects

EI_DATA(Data):

​ 指定了在object文件中特定处理器数据的编码方式。当前定义了以下编码方式。

	Name           Value  Meaning
    ====           =====  =======
    ELFDATANONE        0  Invalid data encoding
    ELFDATA2LSB        1  See below
    ELFDATA2MSB        2  See below

e_type(Type):

​ 指出object的类型:

  Name    Value Meaning
  ====    ===== =======
  ET_NONE     0 No file type
  ET_REL     1 Relocatable file
  ET_EXEC     2 Executable file
  ET_DYN     3 Shared object file
  ET_CORE     4 Core file
  ET_LOPROC 0xff00 Processor-specific
  ET_HIPROC 0xffff Processor-specific

e_machine(Machine):

​ 指出该程序需要的体系结构。

       Name      Value  Meaning
       ====      =====  =======
       EM_NONE       0  No machine
       EM_M32        1  AT&T WE 32100
       EM_SPARC      2  SPARC
       EM_386        3  Intel 80386
       EM_68K        4  Motorola 68000
       EM_88K        5  Motorola 88000
       EM_860        7  Intel 80860
       EM_MIPS       8  MIPS RS3000

e_version(Version):

​ 确定object文件的版本,1表示原来的文件格式,创建新的版本就用大于1的数

     Name         Value  Meaning
     ====         =====  =======
     EV_NONE          0  Invalid version
     EV_CURRENT       1  Current version

e_entry(Entry point address):

​ 系统第一个传输控制的虚拟地址,在那启动进程。假如文件没有如何关联的入口点,该成员就保持为0。

e_flags(flags):

​ 保存着相关文件的特定处理器标志。

e_ehsize(size of section headers):

​ 保存着ELF头大小(以字节计数)

e_phentsize(size of program headers)

​ 保存着在文件的程序头表(program header table)中一个入口的大小(以字节计数)。所有的入口都是同样的大小。

e_phnum(number of program headers):

​ 保存着在程序头表中入口的个数。因此,e_phentsize和e_phnum的乘机就是表的大小(以字节计数).假如没有程序头表(program header table),

e_phnum变量为0。

e_shentsize(Size of section headers):

​ 保存着section头的大小(以字节计数)。一个section头是在section头表(section header table)的一个入口;所有的入口都是同样的大小。

e_shnum(number of section headers):

​ 保存着在section header table中的入口数目。因此,e_shentsize和e_shnum的乘积就是section头表的大小(以字节计数)。假如文件没有section头表,e_shnum值为0。

e_shstrndx(Section header string table index )

​ 保存着跟section名字字符表相关入口的section头表(section header table)索引。假如文件中没有section名字字符表,该变量值为SHN_UNDEF。更详细的信息 看下面“Sections”和字符串表(“String Table”) 。



ELF Section



Section Header

  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;

sh_name(Name):

​ 这个section的名字。它的值是section报头字符表section的索引。, 以NULL空字符结束。

sh_type(Type):

  Name               Value
  ====               =====
  SHT_NULL               0  
  该section头是无效的;它没有相关的section。
  SHT_PROGBITS           1
  该section保存被程序定义了的一些信息,它的格式和意义取决于程序本身。
  SHT_SYMTAB             2
  sections保存着一个符号表(symbol table)
  SHT_STRTAB          	 3
  该section保存着一个字符串表。
  SHT_RELA          	 4
  该section保存着具有明确加数的重定位入口。
  SHT_HASH               5
  该标号保存着一个标号的哈希(hash)表
  SHT_DYNAMIC            6
  该section保存着动态连接的信息。
  SHT_NOTE               
  该section保存着其他的一些标志文件的信息
  SHT_NOBITS             8
  该类型的section在文件中不占空间,但是类似SHT_PROGBITS
  SHT_REL                9
  该section保存着具有明确加数的重定位的入口
  SHT_SHLIB             10
  该section类型保留但语意没有指明。包含这个类型的section的程序
  是不符合ABI的。(应用程序二进制接口)
  SHT_DYNSYM            11
  保存着一个动态连接时所需最小的标号集合来节省空间
  SHT_LOPROC    0x70000000
  在这范围之间的值为特定处理器语意保留的。
  SHT_HIPROC    0x7fffffff
  在这范围之间的值为特定处理器语意保留的。
  SHT_LOUSER    0x80000000
  为应用程序保留的索引范围的最小边界
  SHT_HIUSER    0xffffffff
  为应用程序保留的索引范围的最大边界


sh_flags(FLG):

​ 支持位的标记,用来描述多个属性。

sh_addr(Addr):

​ 出了一个该section在内存中的位置。若不出现在进程的内存映象空间里该变量为0。

sh_offset(Off):

​ section的字节偏移量(从文件开始计数)

sh_size(Size):

​ section的字节大小。除非这个section的类型为SHT_NOBITS,否则该section将在文件中将占sh_size个字节。SHT_NOBITS类型的section可能为非0的大小,但是不占文件空间。

sh_link(Lk):

​ 保存了一个section报头表的索引连接,它的解释依靠该section的类型。以下一个表描述了这些值。

sh_info(Inf):

​ 保存着额外的信息,它的解释依靠该section的类型。以下一个表描述了这些值。

sh_addralign(AL):

​ 一些sections有地址对齐的约束。例如,假如一个section保存着双字,系统就必须确定整个section是否双字对齐。所以sh_addr的值以sh_addralign的值作为模,那么一定为0。当然的,仅仅0和正的2的次方是允许的。值0和1意味着该section没有对齐要求。

sh_entsize(ES):

​ 一些sections保存着一张固定大小入口的表,就象符号表。



Special Sections


Section Headers:
     Name              Type        
                       NULL        
     .interp           PROGBITS    
     .note.ABI-tag     NOTE        
     .note.gnu.build-i NOTE        
     .gnu.hash         GNU_HASH    
     .dynsym           DYNSYM      
     .dynstr           STRTAB      
     .gnu.version      VERSYM      
     .gnu.version_r    VERNEED     
     .rel.dyn          REL         
     .rel.plt          REL         
     .init             PROGBITS    
     .plt              PROGBITS    
     .plt.got          PROGBITS    
     .text             PROGBITS    
     .fini             PROGBITS    
     .rodata           PROGBITS    
     .eh_frame_hdr     PROGBITS    
     .eh_frame         PROGBITS    
     .init_array       INIT_ARRAY  
     .fini_array       FINI_ARRAY  
     .jcr              PROGBITS    
     .dynamic          DYNAMIC     
     .got              PROGBITS    
     .got.plt          PROGBITS    
     .data             PROGBITS    
     .bss              NOBITS      
     .comment          PROGBITS    
     .shstrtab         STRTAB      

.bss:

​ 保存着未初始化的数据,这些数据存在于程序内存映象中。通过定义,当程序开始运行,系统初始化那些数据为0。该section不占文件空间,正如它的section类型SHT_NOBITS指示的一样。

.comment

​ 保存着版本控制信息。

.data and .data1

​ 保存着初始化了的数据,那些数据存在于程序内存映象中。

.debug

​ 保存着为标号调试的信息。该内容是未指明的。

.dynamic

​ 保存着动态连接的信息。该section的属性将包括SHF_ALLOC位。是否需要SHF_WRITE是跟处理器有关。第二部分有更详细的信息。

.dynstr

​ 保存着动态连接时需要的字符串,一般情况下,名字字符串关联着符号表的入口。第二部分有更详细的信息。

.dynsym

​ 保存着动态符号表,如“Symbol Table”的描述。第二部分有更详细的信息。

.fini

​ 保存着可执行指令,它构成了进程的终止代码。因此,当一个程序正常退出时,系统安排执行这个section的中的代码。

.got

​ 保存着全局的偏移量表。看第一部分的“Special Sections”和第二部分的“Global Offset Table”获得更多的信息。

.hash

​ 保存着一个标号的哈希表。

.init

​ 保存着可执行指令,它构成了进程的初始化代码。因此,当一个程序开始运行时,在main函数被调用之前(c语言称为main),系统安排执行这个section的中的代码。

.interp

​ 保存了程序的解释程序(interpreter)的路径。假如在这个section中有一个可装载的段,那么该section的属性的SHF_ALLOC位将被设置;否则,该位不会被设置。

.line

​ 包含编辑字符的行数信息,它描述源程序与机器代码之间的对于关系。该section内容不明确的。

.note

​ 该section保存一些信息。

.plt

​ 该section保存着过程连接表(Procedure Linkage Table)。

.rel and .rela

​ 这些section保存着重定位的信息

.rodata and .rodata1

​ 保存着只读数据,在进程映象中构造不可写的段。

.shstrtab

​ 该section保存着section名称。

.strtab

​ 保存着字符串,一般地,描述名字的字符串和一个标号的入口相关联。

.symtab

​ 该section保存着一个符号表,正如在这个section里“Symbol Table’’的描述。

.text

​ 保存着程序的“text’’或者说是可执行指令。

以上就是ELF文件中的文件头和段头的内容后续还有很多内容需要了解。未必需要完全记忆,但是理解和了解是必要的。

参考文章

《CTF特训营》

http://blog.chinaunix.net/uid-1835494-id-2831795.html



版权声明:本文为qq_43390703原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。