分析平台: x86_64机器
简单的C程序
$ cat hello.c
int main() {
return 0;
}
将该文件用gcc 编译成可重定位文件, 利用hexdump -C得到其16进制的文本(用vim -b 打开, 再用:%!xxd -g 1也可以得到)
$ gcc hello.c -c
$ hexdump -C hello.o
得到的文本:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 00 00 00 00 00 00 00 00 10 02 00 00 00 00 00 00 |................|
00000030 00 00 00 00 40 00 00 00 00 00 40 00 0b 00 0a 00 |....@.....@.....|
00000040 55 48 89 e5 b8 00 00 00 00 5d c3 00 47 43 43 3a |UH.......]..GCC:|
00000050 20 28 47 4e 55 29 20 38 2e 35 2e 30 20 32 30 32 | (GNU) 8.5.0 202|
00000060 31 30 35 31 34 20 28 52 65 64 20 48 61 74 20 38 |10514 (Red Hat 8|
00000070 2e 35 2e 30 2d 31 30 29 00 00 00 00 00 00 00 00 |.5.0-10)........|
00000080 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 |.........zR..x..|
00000090 1b 0c 07 08 90 01 00 00 1c 00 00 00 1c 00 00 00 |................|
000000a0 00 00 00 00 0b 00 00 00 00 41 0e 10 86 02 43 0d |.........A....C.|
000000b0 06 46 0c 07 08 00 00 00 00 00 00 00 00 00 00 00 |.F..............|
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000d0 01 00 00 00 04 00 f1 ff 00 00 00 00 00 00 00 00 |................|
000000e0 00 00 00 00 00 00 00 00 00 00 00 00 03 00 01 00 |................|
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000100 00 00 00 00 03 00 02 00 00 00 00 00 00 00 00 00 |................|
00000110 00 00 00 00 00 00 00 00 00 00 00 00 03 00 03 00 |................|
00000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000130 00 00 00 00 03 00 05 00 00 00 00 00 00 00 00 00 |................|
00000140 00 00 00 00 00 00 00 00 00 00 00 00 03 00 06 00 |................|
00000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000160 00 00 00 00 03 00 04 00 00 00 00 00 00 00 00 00 |................|
00000170 00 00 00 00 00 00 00 00 09 00 00 00 12 00 01 00 |................|
00000180 00 00 00 00 00 00 00 00 0b 00 00 00 00 00 00 00 |................|
00000190 00 68 65 6c 6c 6f 2e 63 00 6d 61 69 6e 00 00 00 |.hello.c.main...|
000001a0 20 00 00 00 00 00 00 00 02 00 00 00 02 00 00 00 | ...............|
000001b0 00 00 00 00 00 00 00 00 00 2e 73 79 6d 74 61 62 |..........symtab|
000001c0 00 2e 73 74 72 74 61 62 00 2e 73 68 73 74 72 74 |..strtab..shstrt|
000001d0 61 62 00 2e 74 65 78 74 00 2e 64 61 74 61 00 2e |ab..text..data..|
000001e0 62 73 73 00 2e 63 6f 6d 6d 65 6e 74 00 2e 6e 6f |bss..comment..no|
000001f0 74 65 2e 47 4e 55 2d 73 74 61 63 6b 00 2e 72 65 |te.GNU-stack..re|
00000200 6c 61 2e 65 68 5f 66 72 61 6d 65 00 00 00 00 00 |la.eh_frame.....|
00000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000250 1b 00 00 00 01 00 00 00 06 00 00 00 00 00 00 00 |................|
00000260 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000270 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000280 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000290 21 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 |!...............|
000002a0 00 00 00 00 00 00 00 00 4b 00 00 00 00 00 00 00 |........K.......|
000002b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000002c0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000002d0 27 00 00 00 08 00 00 00 03 00 00 00 00 00 00 00 |'...............|
000002e0 00 00 00 00 00 00 00 00 4b 00 00 00 00 00 00 00 |........K.......|
000002f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000300 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000310 2c 00 00 00 01 00 00 00 30 00 00 00 00 00 00 00 |,.......0.......|
00000320 00 00 00 00 00 00 00 00 4b 00 00 00 00 00 00 00 |........K.......|
00000330 2e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000340 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
00000350 35 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |5...............|
00000360 00 00 00 00 00 00 00 00 79 00 00 00 00 00 00 00 |........y.......|
00000370 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000380 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000390 4a 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 |J...............|
000003a0 00 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 |................|
000003b0 38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |8...............|
000003c0 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000003d0 45 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00 |E.......@.......|
000003e0 00 00 00 00 00 00 00 00 a0 01 00 00 00 00 00 00 |................|
000003f0 18 00 00 00 00 00 00 00 08 00 00 00 06 00 00 00 |................|
00000400 08 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00000410 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 |................|
00000420 00 00 00 00 00 00 00 00 b8 00 00 00 00 00 00 00 |................|
00000430 d8 00 00 00 00 00 00 00 09 00 00 00 08 00 00 00 |................|
00000440 08 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00000450 09 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
00000460 00 00 00 00 00 00 00 00 90 01 00 00 00 00 00 00 |................|
00000470 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000480 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000490 11 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|
000004a0 00 00 00 00 00 00 00 00 b8 01 00 00 00 00 00 00 |................|
000004b0 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |T...............|
000004c0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000004d0
可利用二进制工具readelf, objdump来分析该可重定位文件是怎么排列的.
分析可重定位文件(hello.o)
可以看到分文件由"*"号附近分为两部分(都是十六进制):
- 00000000~00000200
- 00000210~ 00000250~ 000004c0
第1部分是ELF头和各个section的内容. 第2部分是描述各个sction的section header的结构体内容.
$ readelf -h hello.o
ELF 头:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
类别: ELF64
数据: 2 补码,小端序 (little endian)
版本: 1 (current)
OS/ABI: UNIX - System V
ABI 版本: 0
类型: REL (可重定位文件)
系统架构: Advanced Micro Devices X86-64
版本: 0x1
入口点地址: 0x0
程序头起点: 0 (bytes into file)
Start of section headers: 528 (bytes into file)
标志: 0x0
本头的大小: 64 (字节)
程序头大小: 0 (字节)
Number of program headers: 0
节头大小: 64 (字节)
节头数量: 11
字符串表索引节头: 10
可以看到section header是从528(十六进制为210)开始的, 且节头为64字节:
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;
利用
readelf -SW hello.o
可以得到各个section的信息:
There are 11 section headers, starting at offset 0x210:
节头:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000000000 000040 00000b 00 AX 0 0 1
[ 2] .data PROGBITS 0000000000000000 00004b 000000 00 WA 0 0 1
[ 3] .bss NOBITS 0000000000000000 00004b 000000 00 WA 0 0 1
[ 4] .comment PROGBITS 0000000000000000 00004b 00002e 01 MS 0 0 1
[ 5] .note.GNU-stack PROGBITS 0000000000000000 000079 000000 00 0 0 1
[ 6] .eh_frame PROGBITS 0000000000000000 000080 000038 00 A 0 0 8
[ 7] .rela.eh_frame RELA 0000000000000000 0001a0 000018 18 I 8 6 8
[ 8] .symtab SYMTAB 0000000000000000 0000b8 0000d8 18 9 8 8
[ 9] .strtab STRTAB 0000000000000000 000190 00000e 00 0 0 1
[10] .shstrtab STRTAB 0000000000000000 0001b8 000054 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)
00000210~ 00000250全是0, 对于index[0]的section. 同理,下面的也是各个section header. 下一个的sh_name 1b为偏移, 刚好为1b8+1b=1d3 是.text的名字, 以此类推.
可以看到其偏移为40, 大小为b, 使用objdump -dr hello.o可以看到其二进制代码为:
$objdump -dr hello.o
hello.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: 5d pop %rbp
a: c3 retq
而对应的偏移[0x40,0x40 + 0xb)的位置信息: 55 48 89 e5 b8 00 00 00 00 5d c3 刚好为该段代码的二进制.
接下来节.data, .bss大小都为0 .comment是[0x4b, 0x4b+2e), 即[0x4b, 0x79), 从二进制看 00000040 00 47 43 43 3a 00000050 20 28 47 4e 55 29 20 38 2e 35 2e 30 20 32 30 32 00000060 31 30 35 31 34 20 28 52 65 64 20 48 61 74 20 38 00000070 2e 35 2e 30 2d 31 30 29 00
为comment信息 GCC: (GNU) 8.5.0 210514 (Red Hat 8.5.0-10)
接下来是.note.GNU-stack, 大小都为0.
接着是.eh_frame [0x80, 0x80+38), 因为对其是8, 所以从0x80开始. 具体内容有兴趣可继续研究.
接下来是.symtab, [0xb8, 0xb8+0xd8), 即[0xb8, 0x190), typedef struct { Elf64_Word st_name; /* Symbol name (string tbl index) / unsigned char st_info; / Symbol type and binding / unsigned char st_other; / Symbol visibility / Elf64_Section st_shndx; / Section index / Elf64_Addr st_value; / Symbol value / Elf64_Xword st_size; / Symbol size */ } Elf64_Sym; 共9个符号入口9x24=216=0xb8
接下来是.rela.eh_frame是放了一个重定位, 对于该机器来说, 一个重定位大小为0x18,即24字节. 为 typedef struct elf_internal_rela { bfd_vma r_offset; /* Location at which to apply the action / bfd_vma r_info; / Index and Type of relocation / bfd_vma r_addend; / Constant addend used to compute value */ } Elf_Internal_Rela; 内容; 所以该节大小都是24(0x18)的整数倍.
…
参考文献
Linux ELF 详解2 – Section Header & Section https://blog.csdn.net/helowken2/article/details/113757332
|