学了点PE
文件格式,现在可以趁热打铁,来学习一下ELF
文件格式。
ELF文件格式概述
ELF
文件全称为Executable and Linkable Format
的缩写,中文意思其实就是可执行和可链接格式 。其实ELF
文件分为三大类:
可执行文件无后缀
可重定位文件.o
共享的目标文件(动态链接库).so
ELF
文件格式总体上就是如下图所示,这里介绍都是以64位的ELF
文件做介绍:
1 2 3 4 5 6 7 8 9 +------------------------+ | ELF Header | # ELF文件的基本信息 +------------------------+ | Program Header Table | # 程序头表(用于运行时加载) +------------------------+ | Sections (.text, .data, .bss, .rodata, .symtab, .strtab, .got, .plt等) +------------------------+ | Section Headers | # 各个节的元数据 +------------------------+
ELF
文件结构体有如下,下图主要描述的是没有载入内存中的sections
而不是载入内存中的Segment
:
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 Elf64_Ehdr Elf64_Phdr Sections .null .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .plt.sec .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .dynamic .got .got.plt .data .bss .comment .symtab .strtab .shstrtab .dynstr .dynsym .gnu.hash .note.ABI-tag .note.gnu.build-id .note.gnu.property .interp Elf64_Shdr
下图展现了两种视图,给出了ELF
文件的两种视角:
链接视图,从编译器/链接器角度出发,方便将代码组织成可重定位文件或者可执行文件,该文件放在磁盘中的状态
执行视图,从加载起/运行时角度出发,方便将ELF文件加载到内存中执行,该文件载入到内存中的状态
在磁盘中对应的一些Section1
这里我们就称为节,而载入到内存后就变成Segment
我们称为段
可以使用readelf -S ./lab1
查看全部的Section
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 There are 37 section headers, starting at offset 0x45e8 : Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0 ] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1 ] .gnu.version VERSYM 0000000000000612 00000612 0000000000000020 0000000000000002 A 31 0 2 [ 2 ] .gnu.version_r VERNEED 0000000000000638 00000638 0000000000000020 0000000000000000 A 30 1 8 [ 3 ] .rela.dyn RELA 0000000000000658 00000658 0000000000000108 0000000000000018 A 31 0 8 [ 4 ] .rela.plt RELA 0000000000000760 00000760 00000000000000 a8 0000000000000018 AI 31 18 8 [ 5 ] .init PROGBITS 0000000000001000 00001000 000000000000001b 0000000000000000 AX 0 0 4 [ 6 ] .plt PROGBITS 0000000000001020 00001020 0000000000000080 0000000000000010 AX 0 0 16 [ 7 ] .plt.got PROGBITS 00000000000010 a0 000010 a0 0000000000000010 0000000000000010 AX 0 0 16 [ 8 ] .plt.sec PROGBITS 00000000000010b 0 000010b 0 0000000000000070 0000000000000010 AX 0 0 16 [ 9 ] .text PROGBITS 0000000000001120 00001120 00000000000003 d5 0000000000000000 AX 0 0 16 [10 ] .fini PROGBITS 00000000000014f 8 000014f 8 000000000000000 d 0000000000000000 AX 0 0 4 [11 ] .rodata PROGBITS 0000000000002000 00002000 0000000000000252 0000000000000000 A 0 0 8 [12 ] .eh_frame_hdr PROGBITS 0000000000002254 00002254 0000000000000044 0000000000000000 A 0 0 4 [13 ] .eh_frame PROGBITS 0000000000002298 00002298 0000000000000108 0000000000000000 A 0 0 8 [14 ] .init_array INIT_ARRAY 0000000000003 de8 00002 de8 0000000000000008 0000000000000008 WA 0 0 8 [15 ] .fini_array FINI_ARRAY 0000000000003 df0 00002 df0 0000000000000008 0000000000000008 WA 0 0 8 [16 ] .dynamic DYNAMIC 0000000000003 df8 00002 df8 00000000000001e0 0000000000000010 WA 30 0 8 [17 ] .got PROGBITS 0000000000003f d8 00002f d8 0000000000000028 0000000000000008 WA 0 0 8 [18 ] .got.plt PROGBITS 0000000000004000 00003000 0000000000000050 0000000000000008 WA 0 0 8 [19 ] .data PROGBITS 0000000000004050 00003050 0000000000000010 0000000000000000 WA 0 0 8 [20 ] .bss NOBITS 0000000000004060 00003060 0000000000000030 0000000000000000 WA 0 0 32 [21 ] .comment PROGBITS 0000000000000000 00003060 000000000000002b 0000000000000001 MS 0 0 1 [22 ] .debug_aranges PROGBITS 0000000000000000 0000308b 0000000000000030 0000000000000000 0 0 1 [23 ] .debug_info PROGBITS 0000000000000000 000030b b 00000000000003e0 0000000000000000 0 0 1 [24 ] .debug_abbrev PROGBITS 0000000000000000 0000349b 0000000000000101 0000000000000000 0 0 1 [25 ] .debug_line PROGBITS 0000000000000000 0000359 c 00000000000001 a4 0000000000000000 0 0 1 [26 ] .debug_str PROGBITS 0000000000000000 00003740 000000000000030b 0000000000000001 MS 0 0 1 [27 ] .symtab SYMTAB 0000000000000000 00003 a50 0000000000000780 0000000000000018 28 52 8 [28 ] .strtab STRTAB 0000000000000000 000041 d0 00000000000002 af 0000000000000000 0 0 1 [29 ] .shstrtab STRTAB 0000000000000000 0000447f 0000000000000163 0000000000000000 0 0 1 [30 ] .dynstr STRTAB 0000000000005000 00005000 00000000000000 c9 0000000000000000 A 0 0 8 [31 ] .dynsym DYNSYM 00000000000050 d0 000050 d0 0000000000000180 0000000000000018 A 30 1 8 [32 ] .gnu.hash GNU_HASH 0000000000005250 00005250 0000000000000034 0000000000000000 A 31 0 8 [33 ] .note.ABI-tag NOTE 00000000000052 a8 000052 a8 0000000000000020 0000000000000000 A 0 0 4 [34 ] .note.gnu.bu[...] NOTE 00000000000052 c8 000052 c8 0000000000000024 0000000000000000 A 0 0 4 [35 ] .note.gnu.pr[...] NOTE 00000000000052f 0 000052f 0 0000000000000020 0000000000000000 A 0 0 8 [36 ] .interp PROGBITS 0000000000006000 00006000 000000000000000 d 0000000000000000 A 0 0 8
也可以使用readelf -l --segments ./lab1
查看全部的segments
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x0000000000000380 0x0000000000000380 R 0x8 LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000808 0x0000000000000808 R 0x1000 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338 0x0000000000000020 0x0000000000000020 R 0x8 LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000000505 0x0000000000000505 R E 0x1000 LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000 0x00000000000003a0 0x00000000000003a0 R 0x1000 GNU_EH_FRAME 0x0000000000002254 0x0000000000002254 0x0000000000002254 0x0000000000000044 0x0000000000000044 R 0x4 LOAD 0x0000000000002de8 0x0000000000003de8 0x0000000000003de8 0x0000000000000278 0x00000000000002a8 RW 0x1000 GNU_RELRO 0x0000000000002de8 0x0000000000003de8 0x0000000000003de8 0x0000000000000218 0x0000000000000218 R 0x1 DYNAMIC 0x0000000000002df8 0x0000000000003df8 0x0000000000003df8 0x00000000000001e0 0x00000000000001e0 RW 0x8 LOAD 0x0000000000005000 0x0000000000005000 0x0000000000005000 0x0000000000000310 0x0000000000000310 RW 0x1000 NOTE 0x00000000000052a8 0x00000000000052a8 0x00000000000052a8 0x0000000000000020 0x0000000000000020 R 0x4 NOTE 0x00000000000052c8 0x00000000000052c8 0x00000000000052c8 0x0000000000000024 0x0000000000000024 R 0x4 NOTE 0x00000000000052f0 0x00000000000052f0 0x00000000000052f0 0x0000000000000020 0x0000000000000020 R 0x8 INTERP 0x0000000000006000 0x0000000000006000 0x0000000000006000 0x000000000000000d 0x000000000000000d R 0x1 [Requesting program interpreter: ./ld-2.31 .so] LOAD 0x0000000000006000 0x0000000000006000 0x0000000000006000 0x0000000000000010 0x0000000000000010 RW 0x1000 Section to Segment mapping: Segment Sections... 00 01 .gnu.version .gnu.version_r .rela.dyn .rela.plt 02 03 04 .init .plt .plt.got .plt.sec .text .fini 05 .rodata .eh_frame_hdr .eh_frame 06 .eh_frame_hdr 07 .init_array .fini_array .dynamic .got .got.plt .data .bss 08 .init_array .fini_array .dynamic .got 09 .dynamic 10 .dynstr .dynsym .gnu.hash .note.ABI-tag .note.gnu.build-id .note.gnu.property 11 .note.ABI-tag 12 .note.gnu.build-id 13 .note.gnu.property 14 .interp 15 .interp
ELF文件格式
详细了解一下ELF
文件格式,ELF文件格式相关结构体基本上都在glibc/elf/elf.h
这个头文件中
e_ident
ELF64_Ehdr
这个结构体其实就是ELF
文件头。其结构体如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 typedef struct { unsigned char e_ident[EI_NIDENT]; Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx; } Elf64_Ehdr;
Elf64_Ehdr
在这个所在的位置就是ELF
文件的开头前0x40
字节
开头第一行是e_ident
这个数组,这个数组记录了如下信息
1 2 3 4 5 6 7 8 file_identification ei_class_2 ei_data ei_version ei_osabi ei_abiversion ei_pad ei_nident_size
e_type~e_entry
这几个标识其实都非常重要,尤其是e_entry
标明了程序的入口地址
1 2 3 4 Elf64_Half e_type; Elf64_Half e_machine; Elf64_Word e_version; Elf64_Addr e_entry;
e_phoff与e_shoff
1 2 Elf64_Off e_phoff; Elf64_Off e_shoff;
e_flags~e_shstrndx
1 2 3 4 5 6 7 8 Elf64_Word e_flags; Elf64_Half e_ehsize; Elf64_Half e_phentsize; Elf64_Half e_phnum; Elf64_Half e_shentsize; Elf64_Half e_shnum; Elf64_Half e_shstrndx;
程序头表的开始是0x40
位置,也就是ELF文件头中的e_phoff
的值,并且程序头表相当于Elf64_Phdr phd[count]
这样的一个结构体数组。这里就拿一个分析结构即可。
并且每个程序头表的大小在ELF文件头中已经指明了即Elf64_Half e_shentsize
,这里其实在AWDP
上通防的时候已经接触到了
1 2 3 4 5 6 7 8 9 10 11 typedef struct { Elf64_Word p_type; Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; } Elf64_Phdr;
p_type与p_flags
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Elf64_Word p_type; 0x00000000 PT_NULL 0x00000001 PT_LOAD 0x00000002 PT_DYNAMIC 0x00000003 PT_INTERP 0x00000004 PT_NOTE 0x00000006 PT_PHDR Elf64_Word p_flags; 0x1 PF_X 可执行0x2 PF_W 可写0x4 PF_R 可读
p_offset与p_vaddr
p_offset
表示该段在文件中的起始地址,而p_vaddr
表示该段在内存中的起始地址。由于该程序开启了PIE
保护,所以该ELF
文件中p_offset
与p_vaddr
的值是一样的。
如果没有开启PIE
保护,一般会是0x400040
程序载入到内存中一般基址都为0x400000
(在64位下),下面就是另一个没有开PIE保护的程序,就会发现p_offset
和p_vaddr
不同
p_filesz~p_align
1 2 3 4 Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align;
1 2 3 4 5 6 7 8 9 10 11 12 13 typedef struct { Elf64_Word sh_name; Elf64_Word sh_type; Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize; } Elf64_Shdr;
sh_name~sh_flags
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Elf64_Word sh_name; Elf64_Word sh_type; 0x0 SHT_NULL 0x1 SHT_PROGBITS 0x2 SHT_SYMTAB 0x3 SHT_STRTAB 0x4 SHT_RELA 0x9 SHT_REL 0xB SHT_DYNSYM Elf64_Xword sh_flags; 0x1 SHF_WRTE 0x2 SHF_ALLOC 0x4 SHF_EXECINSTR
sh_addr~sh_offset
sh_offset
其实就是该节头对应的节在文件的起始地址,而sh_addr
就是程序运行时虚拟地址的起始位置
sh_size~sh_entsize
1 2 3 4 5 Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; Elf64_Xword sh_addralign; Elf64_Xword sh_entsize;
ELF64_Chdr
1 2 3 4 5 6 7 typedef struct { Elf64_Word ch_type; Elf64_Word ch_reserved; Elf64_Xword ch_size; Elf64_Xword ch_addralign; } Elf64_Chdr;
ELF64_Sym
1 2 3 4 5 6 7 8 9 typedef struct { Elf64_Word st_name; unsigned char st_info; unsigned char st_other; Elf64_Section st_shndx; Elf64_Addr st_value; Elf64_Xword st_size; } Elf64_Sym;
ELF64_Syminfo
1 2 3 4 5 typedef struct { Elf64_Half si_boundto; Elf64_Half si_flags; } Elf64_Syminfo;
ELF64_Rel
1 2 3 4 5 6 typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; } Elf64_Rel;
ELF64_Rela
1 2 3 4 5 6 typedef struct { Elf64_Addr r_offset; Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela;
ELF64_Dyn
1 2 3 4 5 6 7 8 9 typedef struct { Elf64_Sxword d_tag; union { Elf64_Xword d_val; Elf64_Addr d_ptr; } d_un; } Elf64_Dyn;
ELF64_Verdef
1 2 3 4 5 6 7 8 9 10 11 typedef struct { Elf64_Half vd_version; Elf64_Half vd_flags; Elf64_Half vd_ndx; Elf64_Half vd_cnt; Elf64_Word vd_hash; Elf64_Word vd_aux; Elf64_Word vd_next; } Elf64_Verdef;
ELF64_Verdaux
1 2 3 4 5 6 typedef struct { Elf64_Word vda_name; Elf64_Word vda_next; } Elf64_Verdaux;
ELF64_Verneed
1 2 3 4 5 6 7 8 9 10 typedef struct { Elf64_Half vn_version; Elf64_Half vn_cnt; Elf64_Word vn_file; Elf64_Word vn_aux; Elf64_Word vn_next; } Elf64_Verneed;
ELF64_Vernaux
1 2 3 4 5 6 7 8 9 10 typedef struct { Elf64_Word vna_hash; Elf64_Half vna_flags; Elf64_Half vna_other; Elf64_Word vna_name; Elf64_Word vna_next; } Elf64_Vernaux;
ELF64_auxv_t
1 2 3 4 5 6 7 8 9 10 11 typedef struct { uint64_t a_type; union { uint64_t a_val; } a_un; } Elf64_auxv_t;
ELF64_Nhdr
1 2 3 4 5 6 typedef struct { Elf64_Word n_namesz; Elf64_Word n_descsz; Elf64_Word n_type; } Elf64_Nhdr;
ELF64_Move
1 2 3 4 5 6 7 8 9 typedef struct { Elf64_Xword m_value; Elf64_Xword m_info; Elf64_Xword m_poffset; Elf64_Half m_repeat; Elf64_Half m_stride; } Elf64_Move;
ELF64_Lib
1 2 3 4 5 6 7 8 typedef struct { Elf64_Word l_name; Elf64_Word l_time_stamp; Elf64_Word l_checksum; Elf64_Word l_version; Elf64_Word l_flags; } Elf64_Lib;