ELF 文件数据分析: 全局变量

先编译一个简单的 C 程序。

#include <stdio.h>

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

hello: file format elf32-i386

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,其他代码省略

080483c4 <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

0001014: c0 84 04 08 34 12 00 00 00 47 43 43 3a 20 28 55 ....4....GCC: (U
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

00004c0: 48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21 00 55 62 Hello, World!.Ub
00004d0: 75 6e 74 75 00 00 00 00 00 00 00 00 00 00 00 00 untu............


接下来看看未出化全局变量 x 的情况。

mov DWORD PTR ds:0x804a024,0x80484ce ; 注释: x = "Ubuntu"


很显然,该变量地址 (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

00004ce: 55 62 75 6e 74 75 00 00 00 00 00 00 00 00 00 00 Ubuntu..........
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

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: 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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值