当前位置:   article > 正文

180629 逆向-ELF文件结构_elf二进制文件的头部特征 逆向

elf二进制文件的头部特征 逆向

Linux逆向

ELF文件结构

基本结构

ELF Header
.text
.data
.bss
other sections
Section header table
String Tables
Symbol Tables

文件头

ELF文件头(Elf header)位于最前部,它包含了描述整个文件的基本属性,包括ELF文件版本、目标机器型号、程序入口地址等

readelf -h命令可以查看文件头的相关信息

$ readelf -h ez_crackme
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x7c0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          12588 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         27
  Section header string table index: 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这是将文件头解析出来的结果
各个常量和结构体定义在/usr/include/elf.h中

ELF文件有32位版本和64位版本两种,文件头也有这两种版本,分别叫做Elf32_EhdrElf64_Ehdr
32位版本与64位版本的ELF文件的文件头内容是一样的,只是一些成员由于地址不同而使得大小不同

除了e_ident成员对应了Class, Data, Verion, OS/ABI和ABI Version五个参数以外,其他成员都是一一对应的
以32位为例

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

值得一提的是
- e_ident
共16字节
其中4字节魔数(Magic Number)标识ELF文件
1字节文件类,1表示32位,2表示64位
1字节字节序,表示大小端
1字节主版本号,通常是1(因为ELF标准只到1.2版)
其余9字节未在ELF标准中定义,有些平台会使用它们作为扩展标志
- e_type
标识ELF文件类型
- 可重定位文件(.o)
- 可执行文件
- 共享目标文件(.so)
- e_entry
Entry point address,规定了ELF程序的入口虚拟地址
- e_shoff
Start of section headers,表示段表在文件中的偏移字节数
- e_ehsize
Size of this header,表示文件头的大小
- e_shentsize
Size of section header,表示段表描述符的大小
- e_shnum
Number of section header,表示段表描述符的数量,即ELF文件中拥有几个段
- e_shstrndx
Section header string table index,字符串表在段表中的下标

段表

紧接着是ELF文件各个段,最重要的是段表(Section Header Table),它描述各个段的信息,包括段名、长度、偏移、读写权限等等

通过objdump -h和readelf -s可以读出各个段的信息,不过前者仅列出比较重要的一些段,忽略字符串表等辅助段,而后者将会把所有段全部列出

$ readelf -S ez_crackme
There are 27 section headers, starting at offset 0x312c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        00000154 000154 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            00000168 000168 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            00000188 000188 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        000001ac 0001ac 000034 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          000001e0 0001e0 000110 10   A  6   1  4
  [ 6] .dynstr           STRTAB          000002f0 0002f0 0000f6 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          000003e6 0003e6 000022 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         00000408 000408 000040 00   A  6   1  4
  [ 9] .rel.dyn          REL             00000448 000448 0002f8 08   A  5   0  4
  [10] .init             PROGBITS        00000740 000740 000023 00  AX  0   0  4
  [11] .plt              PROGBITS        00000770 000770 000010 04  AX  0   0 16
  [12] .plt.got          PROGBITS        00000780 000780 000040 00  AX  0   0  8
  [13] .text             PROGBITS        000007c0 0007c0 001872 00  AX  0   0 16
  [14] .fini             PROGBITS        00002034 002034 000014 00  AX  0   0  4
  [15] .rodata           PROGBITS        00002060 002060 0001f6 00   A  0   0 32
  [16] .eh_frame_hdr     PROGBITS        00002258 002258 0000dc 00   A  0   0  4
  [17] .eh_frame         PROGBITS        00002334 002334 0003b4 00   A  0   0  4
  [18] .init_array       INIT_ARRAY      00003ed0 002ed0 000004 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      00003ed4 002ed4 000004 00  WA  0   0  4
  [20] .jcr              PROGBITS        00003ed8 002ed8 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         00003edc 002edc 0000e8 08  WA  6   0  4
  [22] .got              PROGBITS        00003fc4 002fc4 00003c 04  WA  0   0  4
  [23] .data             PROGBITS        00004000 003000 000008 00  WA  0   0  4
  [24] .bss              NOBITS          00004020 003008 000144 00  WA  0   0 32
  [25] .comment          PROGBITS        00000000 003008 000034 01  MS  0   0  1
  [26] .shstrtab         STRTAB          00000000 00303c 0000ed 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

  • 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

段表实际上是一个Elf32_Shdr结构体数组。
这个结构体定义也在elf.h中,又被叫做段描述符

同样以32位为例

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • sh_name
    所有段名存储在shstrtab段中,通过sh_name的值来取字符串
  • sh_type
    表示段的类型
    段名对于编译器和链接器有意义,但对运行它的系统其实是无意义的。因此虽然程序代码通常存放在.text段中,但其实并无规定。
    操作系统仅通过type来识别,包括程序段、符号表、字符串表等等
  • sh_flags
    表示段属性
    1可写
    2映射到内存
    4可执行
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/160564
推荐阅读
相关标签
  

闽ICP备14008679号