先编译一个简单的 C 程序。
char* s = "Hello, World!";
char* x;
int i = 0x1234;
int main(int argc, char* argv[])
{
x = "Ubuntu";
printf("%s/n", s);
return 0;
}
编译后,使用 objdump 输出 ELF Section 信息。我们通常关心只有 .text, .rodata, .data, .bss 这几个段。
yuhen@yuhen-desktop:~/Learn.c$ objdump -h hello
Sections:
Idx Name Size VMA LMA File off Algn
12 .text 0000018c 08048310 08048310 00000310 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .rodata 0000001d 080484b8 080484b8 000004b8 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
22 .data 00000010 0804a00c 0804a00c 0000100c 2**2
CONTENTS, ALLOC, LOAD, DATA
23 .bss 0000000c 0804a01c 0804a01c 0000101c 2**2
ALLOC
Section 说明:
- .text: 程序执行代码。
- .rodata: 代码中的字符串常量等。
- .data: 初始化的全局变量。
- .bss: 未初始化的全局变量。
我们反汇编看看 main 函数中的相关代码。
yuhen@yuhen-desktop:~/Learn.c$ objdump -d -M intel hello > hello.asm
yuhen@yuhen-desktop:~/Learn.c$ cat hello.asm | less # 我们只关心 main,其他代码省略
80483c4: 8d 4c 24 04 lea ecx,[esp+0x4]
80483c8: 83 e4 f0 and esp,0xfffffff0
80483cb: ff 71 fc push DWORD PTR [ecx-0x4]
80483ce: 55 push ebp
80483cf: 89 e5 mov ebp,esp
80483d1: 51 push ecx
80483d2: 83 ec 04 sub esp,0x4
80483d5: c7 05 24 a0 04 08 ce mov DWORD PTR ds:0x804a024,0x80484ce ; 注释: x = "Ubuntu"
80483dc: 84 04 08
80483df: a1 14 a0 04 08 mov eax,ds:0x804a014 ; 注释: s 地址
80483e4: 89 04 24 mov DWORD PTR [esp],eax
80483e7: e8 08 ff ff ff call 80482f4 <puts@plt>
80483ec: b8 00 00 00 00 mov eax,0x0
80483f1: 83 c4 04 add esp,0x4
80483f4: 59 pop ecx
80483f5: 5d pop ebp
80483f6: 8d 61 fc lea esp,[ecx-0x4]
80483f9: c3 ret
80483fa: 90 nop
80483fb: 90 nop
80483fc: 90 nop
80483fd: 90 nop
80483fe: 90 nop
80483ff: 90 nop
我们先关注全局变量 s,其地址是:
0x804a014 - 0x0804a00c (.data 基地址) + 0x0000100c (.data Offset) = 0x1014
我们看看二进制文件中对应位置的信息。
yuhen@yuhen-desktop:~/Learn.c$ xxd -g 1 -s 0x1014 -l 100 hello
0001024: 62 75 6e 74 75 20 34 2e 33 2e 33 2d 35 75 62 75 buntu 4.3.3-5ubu
0001034: 6e 74 75 34 29 20 34 2e 33 2e 33 00 00 47 43 43 ntu4) 4.3.3..GCC
指向 0x080484c0,我们计算一下该字符串的 offset。
0x080484c0 - 0x080484b8 (.rodata 基地址) + 0x000004b8 (.rodata Offset) = 0x04c0
看看数据。
yuhen@yuhen-desktop:~/Learn.c$ xxd -g 1 -s 0x04c0 -l 100 hello
00004d0: 75 6e 74 75 00 00 00 00 00 00 00 00 00 00 00 00 untu............
接下来看看未出化全局变量 x 的情况。
很显然,该变量地址 (0x804a024) 在 .bss 段 (0x0804a01c ~ 0x0804a028)。字符串 "Ubuntu" 地址是 0x80484ce,我们可以计算其 Offset。
0x80484ce - 0x080484b8 (.rodata 基地址) + 0x000004b8 (.rodata Offset) = 0x04ce
yuhen@yuhen-desktop:~/Learn.c$ xxd -g 1 -s 0x04ce -l 100 hello
00004de: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
全局变量和静态变量的地址在编译时就决定了的。我们还可以用 readelf 命令获取更详细的 ELF 文件信息。
yuhen@yuhen-desktop:~/Learn.c$ readelf -e hello
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: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048310
Start of program headers: 52 (bytes into file)
Start of section headers: 6004 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 8
Size of section headers: 40 (bytes)
Number of section headers: 36
Section header string table index: 33
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 08048134 000134 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4
[ 3] .hash HASH 08048168 000168 000028 04 A 5 0 4
[ 4] .gnu.hash GNU_HASH 08048190 000190 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481b0 0001b0 000050 10 A 6 1 4
[ 6] .dynstr STRTAB 08048200 000200 00004a 00 A 0 0 1
[ 7] .gnu.version VERSYM 0804824a 00024a 00000a 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 08048254 000254 000020 00 A 6 1 4
[ 9] .rel.dyn REL 08048274 000274 000008 08 A 5 0 4
[10] .rel.plt REL 0804827c 00027c 000018 08 A 5 12 4
[11] .init PROGBITS 08048294 000294 000030 00 AX 0 0 4
[12] .plt PROGBITS 080482c4 0002c4 000040 04 AX 0 0 4
[13] .text PROGBITS 08048310 000310 00018c 00 AX 0 0 16
[14] .fini PROGBITS 0804849c 00049c 00001c 00 AX 0 0 4
[15] .rodata PROGBITS 080484b8 0004b8 00001d 00 A 0 0 4
[16] .eh_frame PROGBITS 080484d8 0004d8 000004 00 A 0 0 4
[17] .ctors PROGBITS 08049f0c 000f0c 000008 00 WA 0 0 4
[18] .dtors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
[19] .jcr PROGBITS 08049f1c 000f1c 000004 00 WA 0 0 4
[20] .dynamic DYNAMIC 08049f20 000f20 0000d0 08 WA 6 0 4
[21] .got PROGBITS 08049ff0 000ff0 000004 04 WA 0 0 4
[22] .got.plt PROGBITS 08049ff4 000ff4 000018 04 WA 0 0 4
[23] .data PROGBITS 0804a00c 00100c 000010 00 WA 0 0 4
[24] .bss NOBITS 0804a01c 00101c 00000c 00 WA 0 0 4
[25] .comment PROGBITS 00000000 00101c 0000fc 00 0 0 1
[26] .debug_aranges PROGBITS 00000000 001118 000070 00 0 0 8
[27] .debug_pubnames PROGBITS 00000000 001188 000025 00 0 0 1
[28] .debug_info PROGBITS 00000000 0011ad 0001b5 00 0 0 1
[29] .debug_abbrev PROGBITS 00000000 001362 000083 00 0 0 1
[30] .debug_line PROGBITS 00000000 0013e5 000180 00 0 0 1
[31] .debug_str PROGBITS 00000000 001565 00008e 01 MS 0 0 1
[32] .debug_ranges PROGBITS 00000000 0015f8 000040 00 0 0 8
[33] .shstrtab STRTAB 00000000 001638 000139 00 0 0 1
[34] .symtab SYMTAB 00000000 001d14 0004d0 10 35 54 4
[35] .strtab STRTAB 00000000 0021e4 000213 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 R E 0x4
INTERP 0x000134 0x08048134 0x08048134 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x004dc 0x004dc R E 0x1000
LOAD 0x000f0c 0x08049f0c 0x08049f0c 0x00110 0x0011c RW 0x1000
DYNAMIC 0x000f20 0x08049f20 0x08049f20 0x000d0 0x000d0 RW 0x4
NOTE 0x000148 0x08048148 0x08048148 0x00020 0x00020 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
GNU_RELRO 0x000f0c 0x08049f0c 0x08049f0c 0x000f4 0x000f4 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .hash ... .text .fini .rodata .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag
06
07 .ctors .dtors .jcr .dynamic .got