有的逆向题目需要用到ELF,那我就来先了解一下什么是ELF。
1.ELF格式
我们先来看看 ELF 文件头。
继续努力第七天
ELF头部
关于ELF更详细的说明:
e_shoff:节头表的文件偏移量(字节)。如果文件没有节头表,则此成员值为零。
sh_offset:表示了该section(节)离开文件头部位置的距离

±------------------+
| ELF header |—+
±--------> ±------------------+ | e_shoff
| | |<–+
| Section | Section header 0 |
| | |—+ sh_offset
| Header ±------------------+ |
| | Section header 1 |—|–+ sh_offset
| Table ±------------------+ | |
| | Section header 2 |—|–|--+
±--------> ±------------------+ | | |
| Section 0 |<–+ | |
±------------------+ | | sh_offset
| Section 1 |<-----+ |
±------------------+ |
| Section 2 |<--------+
±------------------+

2.可执行头部(Executable Header)
ELF文件的第一部分是可执行文件头部(Executable Header),其中包含有关ELF文件类型的信息。
ELF文件在各种平台下都通用,ELF文件有32位版本和64位版本,其文件头内容是一样的,只不过有些成员的大小不一样。它的文件图也有两种版本:分别叫"Elf32_Ehdr"和"Elf64_Ehdr"。
这里以32位版本为例:

#define EI_NIDENT (16)

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;
使用readelf对ELF文件格式进行分析

readelf -h /bin/ls

ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2’s complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x6130
Start of program headers: 64 (bytes into file)
Start of section headers: 137000 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 11
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
我们可以使用以下计算方法来计算整个二进制文件的大小:

size = e_shoff + (e_shnum * e_shentsize)

size = Start of section headers + (Number of section headers * Size of section headers)

size = 137000 + (29*64) = 138856
计算结果验证:

ls -l /bin/ls

-rwxr-xr-x 1 root root 138856 Aug 29 21:20 /bin/ls

3、程序头部(Program Headers)
程序头部是描述文件中的各种segments(段),用来告诉系统如何创建进程映像的。

typedef struct {
Elf32_Word p_type; /* Segment type /
Elf32_Off p_offset; /
Segment file offset /
Elf32_Addr p_vaddr; /
Segment virtual address /
Elf32_Addr p_paddr; /
Segment physical address /
Elf32_Word p_filesz; /
Segment size in file /
Elf32_Word p_memsz; /
Segment size in memory /
Elf32_Word p_flags; /
Segment flags /
Elf32_Word p_align; /
Segment alignment */
} Elf32_Phdr;
4、节表头部(Section Headers)
节表头部(Section Headers)包含了描述文件节区的信息,比如大小、偏移等,但这些对二进制文件的执行流程来说并不重要。

sections 或者 segments:segments是从运行的角度来描述elf文件,sections是从链接的角度来描述elf文件,也就是说,在链接阶段,我们可以忽略program header table来处理此文件,在运行阶段可以忽略section header table来处理此程序(所以很多加固手段删除了section header table)。从图中我们也可以看出, segments与sections是包含的关系,一个segment包含若干个section。
继续努力第七天

typedef struct {
Elf32_Word sh_name; /* section的名字 (string tbl index) */
Elf32_Word sh_type; /*section类别 /
Elf32_Word sh_flags; /
section在进程中执行的特性(读、写) /
Elf32_Addr sh_addr; /
在内存中开始的虚地址 /
Elf32_Off sh_offset; /
此section在文件中的偏移 /
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;
5、表(Section)
5.1 .bss Section
保存未初始化的数据,比如那些未初始化的全局变量。

5.2 .data Section
保存已初始化的数据。

5.3 .rodata Section
保存程序中的只读数据。

5.4 .text Section
本节包含程序的实际代码,逻辑流程。
使用readelf查看ELF文件表结构

readelf -S --wide /bin/ls

There are 29 section headers, starting at offset 0x21728:

Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00000000000002a8 0002a8 00001c 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 00000000000002c4 0002c4 000020 00 A 0 0 4
[ 3] .note.gnu.build-id NOTE 00000000000002e4 0002e4 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0000000000000308 000308 0000c0 00 A 5 0 8
[ 5] .dynsym DYNSYM 00000000000003c8 0003c8 000c90 18 A 6 1 8
[ 6] .dynstr STRTAB 0000000000001058 001058 0005d8 00 A 0 0 1
[ 7] .gnu.version VERSYM 0000000000001630 001630 00010c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 0000000000001740 001740 000070 00 A 6 1 8
[ 9] .rela.dyn RELA 00000000000017b0 0017b0 001350 18 A 5 0 8
[10] .rela.plt RELA 0000000000002b00 002b00 0009f0 18 AI 5 24 8
[11] .init PROGBITS 0000000000004000 004000 000017 00 AX 0 0 4
[12] .plt PROGBITS 0000000000004020 004020 0006b0 10 AX 0 0 16
[13] .plt.got PROGBITS 00000000000046d0 0046d0 000018 08 AX 0 0 8
[14] .text PROGBITS 00000000000046f0 0046f0 01253e 00 AX 0 0 16
[15] .fini PROGBITS 0000000000016c30 016c30 000009 00 AX 0 0 4
[16] .rodata PROGBITS 0000000000017000 017000 005129 00 A 0 0 32
[17] .eh_frame_hdr PROGBITS 000000000001c12c 01c12c 0008fc 00 A 0 0 4
[18] .eh_frame PROGBITS 000000000001ca28 01ca28 002ed0 00 A 0 0 8
[19] .init_array INIT_ARRAY 0000000000021390 020390 000008 08 WA 0 0 8
[20] .fini_array FINI_ARRAY 0000000000021398 020398 000008 08 WA 0 0 8
[21] .data.rel.ro PROGBITS 00000000000213a0 0203a0 000a38 00 WA 0 0 32
[22] .dynamic DYNAMIC 0000000000021dd8 020dd8 0001f0 10 WA 6 0 8
[23] .got PROGBITS 0000000000021fc8 020fc8 000038 08 WA 0 0 8
[24] .got.plt PROGBITS 0000000000022000 021000 000368 08 WA 0 0 8
[25] .data PROGBITS 0000000000022380 021380 000268 00 WA 0 0 32
[26] .bss NOBITS 0000000000022600 0215e8 0012d8 00 WA 0 0 32
[27] .gnu_debuglink PROGBITS 0000000000000000 0215e8 000034 00 0 0 4
[28] .shstrtab STRTAB 0000000000000000 02161c 00010a 00 0 0 1

Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)

相关文章: