Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2395
  • 博文数量: 2
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2022-07-22 00:46
文章分类
文章存档

2022年(2)

我的朋友
最近访客

分类: LINUX

2022-09-14 11:52:14

原文地址:Linux应用程序elf描述 作者:BugMan

    玩Linux的人应该明白ELF文件是一种文件格式,就好比.txt,.doc等一样,只是这个文件是按照特定信息排列组成,同样在windows上也存在一种格式,它叫PE,老的叫dos。下面我就来看看ELF文件里面到底有什么, 以hello.c为例子。
点击(此处)折叠或打开
  1. #include <stdio.h>

  2. int main (int argc, char *argv[])
  3. {
  4.     printf ("Hello World\n");

  5.     return 0;
  6. }
 图 1
执行:make hello   生成hello可执行文件(ELF格式).
    首先,我们可以通过readelf -h hello,来获取hello这个elf文件的头部信息(该信息放置在hello文件的头部,大小为64字节):
点击(此处)折叠或打开
  1. $ readelf -h hello
  2. ELF Header:
  3. Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  4. Class: ELF64
  5. Data: 2's complement, little endian
  6. Version: 1 (current)
  7. OS/ABI: UNIX - System V
  8. ABI Version: 0
  9. Type: EXEC (Executable file)
  10. Machine: Advanced Micro Devices X86-64
  11. Version: 0x1
  12. Entry point address: 0x400430
  13. Start of program headers: 64 (bytes into file)
  14. Start of section headers: 6696 (bytes into file)
  15. Flags: 0x0
  16. Size of this header: 64 (bytes)
  17. Size of program headers: 56 (bytes)
  18. Number of program headers: 9
  19. Size of section headers: 64 (bytes)
  20. Number of section headers: 31
  21. Section header string table index: 28
图 2 
  当我们在shell命令行敲击./hello的时候,内核是怎么识别这是一个可执行文件(elf文件)的呢?其实,在shell进行运行的时候,busybox会将"./hello"当成execve系统函数参数进行传参即:execve("./hello", ["./hello"]) 。当Linux发生系统调用并陷入内核后,Linux内核将这个hello文件的从0开始的前面几个字节与.ELF(7f 45 4c 46)比较,如果一样,则是elf文件,如果不一样,则与"#!"进行比较,以此来查看是否为需要第三方解释的脚本语言(#!后面跟的是解释器的路径),如#!/bin/sh或者#!/usr/bin/python。
    上面提到的7f 45 4c 46就是一个elf文件的magic,一种固定elf标志即文件的识别码,其对应的ascii码是.ELF, 可以通过readelf -h hello获取到,如图2
    由图2可知,这个ELF文件支持的平台为X86-64,版本是0x1,入口地址是0x400430,段的起始地址是文件偏移6696字节处,Program Header在文件偏移64字节处即elf头信息之后。当前elf header占大小64字节,有9个program header和31个段等等,具体elf header格式,可以参考elf.h头文件。
    温馨小提示:这里我们普及一下什么是section。我们常听说的section有代码段(TEXT段),BSS段,数据段(DATA段),只读数据段(RODATA段),HEAP, STACK等。在C语言中,.TEXT段主要用于存放函数对应的机器码的(也就是可执行程序的可运行部分),BSS段主要存放全局未初始化变量的(数据部分),DATA段主要存放全局并且已经初始化过的变量的(注意:初始化成0/NULL的全局变量会被认为是未初始化而放置到BSS段,因为BSS段的数据默认就是0/NULL),RODATA段用于存放const类型的变量,HEAP主要是分配内存使用,而STACK主要是用于函数调用和函数局部变量使用。
    在讲ELF各个部分内容之前,我们先看看ELF文件的整体结构:


  1. +-----------------------+ hello文件偏移 0bytes
  2. |                       |
  3. |        ELF Header     |
  4. +-----------------------+ hello文件偏移 64bytes
  5. |                       |
  6. |       Program Header  |
  7. +-----------------------+ hello文件偏移 568bytes (64+56 * 9)
  8. |        interpreter    | (动态解释器位置)
  9. +-----------------------+
  10. |          .......      |
  11. +-----------------------+ hello文件偏移 3600bytes
  12. |          text         | (代码段位置)
  13. +-----------------------+
  14. |         ro data       | (只读数据段位置)
  15. +-----------------------+
  16. |        .......        | (其它段)
  17. +-----------------------+
  18. |          data         | (数据段)
  19. +-----------------------+ hello文件偏移 6696bytes
  20. |     Section Header    | (段表位置)
  21. +-----------------------+ hello文件尾部 8680 bytes

点击(此处)折叠或打开

  1. $ ls -l hello
  2. -rwxr-xr-x 1 cliu4 users 8689月 30 14:31 hello
图 3  
    如图3,图为hello文件的整个布局图,从图中可以看出,hello可执行文件的大小为8680字节,其中0-64字节存放的是elf文件的头部信息,即elf header(这个结构体可以通过查看elf.h获取),64字节之后存放的是program header,在之后放的是动态解释器(interpreter),而section header则是放到文件末尾的即6696字节处,中间放到程序段即section。而当我们知道了elf头部信息的作用就是指明当前elf文件的版本号,运行环境和其他段的位置,个数以及大小后,那么紧接着elf header的program header到底又有什么用呢?首先我们看看program header里面到底有什么,如下图:

点击(此处)折叠或打开
  1. readelf -l hello

  2. Elf file type is EXEC (Executable file)
  3. Entry point 0x400430
  4. There are 9 program headers, starting at offset 64

  5. Program Headers:
  6.   Type               Offset           VirtAddr          PhysAddr           FileSiz              MemSiz          Flags Align
  7.   PHDR          0x0000000000000040 0x0000000000400040 0x0000000000400040 0x00000000000001f8 0x00000000000001f8    RE    8
  8.   INTERP       0x0000000000000238 0x0000000000400238 0x0000000000400238 0x000000000000001c 0x000000000000001c    R     1
  9.                [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  10.   LOAD         0x0000000000000000 0x0000000000400000 0x0000000000400000 0x0000000000000794 0x0000000000000794    RE   200000
  11.   LOAD         0x0000000000000e00 0x0000000000600e00 0x0000000000600e00 0x0000000000000238 0x0000000000000240    RW   200000
  12.   DYNAMIC      0x0000000000000e28 0x0000000000600e28 0x0000000000600e28 0x00000000000001d0 0x00000000000001d0    RW    8
  13.   NOTE         0x0000000000000254 0x0000000000400254 0x0000000000400254 0x0000000000000044 0x0000000000000044    R     4
  14.   GNU_EH_FRAME 0x0000000000000618 0x0000000000400618 0x0000000000400618 0x0000000000000044 0x0000000000000044    R     4
  15.   GNU_STACK    0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000    RW    10
  16.   GNU_RELRO    0x0000000000000e00 0x0000000000600e00 0x0000000000600e00 0x0000000000000200 0x0000000000000200    R      1
  17.  Section to Segment mapping:
  18.   Segment Sections...
  19.    00
  20.    01     .interp
  21.    02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
  22.    03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
  23.    04     .dynamic
  24.    05     .note.ABI-tag .note.gnu.build-id
  25.    06     .eh_frame_hdr
  26.    07
  27.    08     .init_array .fini_array .jcr .dynamic .got
图 4
    如图4,program headers包含:1、PHDR(program header起始位置0x40,大小0x1f8);2、INTERP(动态解释器,其实就是一个字符串,记录了动态解释器的位置:/lib64/ld-linux-x86-64.so.2);3、LOAD;4、LOAD;5、DYNAMIC;6、NOTE等。从第20行"Section to Segment mapping"下面可以看到编号00,01,02,03....08,这些编号对应的是program header对应的表,例如:00对应的是PHDR,01对应的是INTERP,02对应的是LOAD等。因此,可以知道01对应的program header INTERP部分记录的是.interp段信息;而其他的与运行相关的记录在02/03对应的LOAD结构当中。那么这个program header到底有什么用呢?其实,这个program header仔细的朋友应该能够发现每个program header都记录了对应所在的文件偏移和内存的虚拟地址和物理地址,当系统调用execve陷入到内核,并且发现这个hello文件为elf文件的时候,Linux内核就会根据program header当中的提示信息来对hello进行内存映射,给hello开辟自己的虚拟地址空间(如LOAD部分虚拟地址是0x400000即图4标红部分),并且通过INTERP获取到当前elf文件的动态解释器路径:/lib64/ld-linux-x86-64.so.2,还可以通过DYNAMIC部分获取到当前hello文件依赖的动态库信息,知道哪些动态库需要引用(readelf -d hello)。因此,我可以简单的理解为:program header信息 就是为Linux内核提供应用程序加载相关的信息,方便内核加载可执行程序。
    如图3,经过了program header,挨着它的便是动态解释器(.interpreter)的位置了,这个地方比较简单,就是一个字符串,指明了动态解释器的路径。这个动态解释器/lib64/ld-linux-x86-64.so.2看起来是一个动态库,其实不是,它是一个可用自我重定位的可执行程序,其主要作用就是帮助hello进行代码重定位。
    如图3,在动态解释器后的具体段,将在section headers之后描述。
    如图3,在文件的末尾,即6696偏移到8680偏移的位置处,存放的是section header。可用通过readelf -S hello获取到。
下图是section headers结构的信息:
点击(此处)折叠或打开
  1. There are 31 section headers, starting at offset 0x1a28:

  2. Section Headers:
  3.   [Nr]  Name Type Address Offset Size EntSize Flags Link Info Align
  4.   [ 0]  NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0
  5.   [ 1] .interp PROGBITS 0000000000400238 00000238 000000000000001c 0000000000000000 A 0 0 1
  6.   [ 2] .note.ABI-tag NOTE 0000000000400254 00000254  0000000000000020 0000000000000000 A 0 0 4
  7.   [ 3] .note.gnu.build-i NOTE 0000000000400274 00000274 0000000000000024 0000000000000000 A 0 0 4
  8.   [ 4] .gnu.hash GNU_HASH 0000000000400298 00000298  000000000000001c 0000000000000000 A 5 0 8
  9.   [ 5] .dynsym DYNSYM 00000000004002b8 000002b8 0000000000000060 0000000000000018 A 6 1 8
  10.   [ 6] .dynstr STRTAB 0000000000400318 00000318 000000000000003d 0000000000000000 A 0 0 1
  11.   [ 7] .gnu.version VERSYM 0000000000400356 00000356 0000000000000008 0000000000000002 A 5 0 2
  12.   [ 8] .gnu.version_r VERNEED 0000000000400360 00000360 0000000000000020 0000000000000000 A 6 1 8
  13.   [ 9] .rela.dyn RELA 0000000000400380 00000380 0000000000000018 0000000000000018 A 5 0 8
  14.   [10] .rela.plt RELA 0000000000400398 00000398 0000000000000030 0000000000000018 AI 5 24 8
  15.   [11] .init PROGBITS 00000000004003c8 000003c8 000000000000001a 0000000000000000 AX 0 0 4
  16.   [12] .plt PROGBITS 00000000004003f0 000003f0 0000000000000030 0000000000000010 AX 0 0 16
  17.   [13] .plt.got PROGBITS 0000000000400420 00000420  0000000000000008 0000000000000000 AX 0 0 8
  18.   [14] .text PROGBITS 0000000000400430 00000430 00000000000001b2 0000000000000000 AX 0 0 16
  19.   [15] .fini PROGBITS 00000000004005e4 000005e4  0000000000000009 0000000000000000 AX 0 0 4
  20.   [16] .rodata PROGBITS 00000000004005f0 000005f0 0000000000000027 0000000000000000 A 0 0 4
  21.   [17] .eh_frame_hdr PROGBITS 0000000000400618 00000618 0000000000000044 0000000000000000 A 0 0 4
  22.   [18] .eh_frame PROGBITS 0000000000400660 00000660 0000000000000134 0000000000000000 A 0 0 8
  23.   [19] .init_array INIT_ARRAY 0000000000600e00 00000e00 0000000000000010 0000000000000000 WA 0 0 8
  24.   [20] .fini_array FINI_ARRAY 0000000000600e10 00000e10  0000000000000010 0000000000000000 WA 0 0 8
  25.   [21] .jcr PROGBITS 0000000000600e20 00000e20 0000000000000008 0000000000000000 WA 0 0 8
  26.   [22] .dynamic DYNAMIC 0000000000600e28 00000e28 00000000000001d0 0000000000000010 WA 6 0 8
  27.   [23] .got PROGBITS 0000000000600ff8 00000ff8 0000000000000008 0000000000000008 WA 0 0 8
  28.   [24] .got.plt PROGBITS 0000000000601000 00001000 0000000000000028 0000000000000008 WA 0 0 8
  29.   [25] .data PROGBITS 0000000000601028 00001028 0000000000000010 0000000000000000 WA 0 0 8
  30.   [26] .bss NOBITS 0000000000601038 00001038 0000000000000008 0000000000000000 WA 0 0 1
  31.   [27] .comment PROGBITS 0000000000000000 00001038 0000000000000035 0000000000000001 MS 0 0 1
  32.   [28] .shstrtab STRTAB 0000000000000000 00001915 000000000000010c 0000000000000000 0 0 1
  33.   [29] .symtab SYMTAB 0000000000000000 00001070 0000000000000678 0000000000000018 30 49 8
  34.   [30] .strtab STRTAB 0000000000000000 000016e8 000000000000022d 0000000000000000 0 0 1
  图 5
    图5是hello文件的section header, 这个信息描述了这个hello文件中到底存在有多少section,这里我将比较重要的section用紫色表示。其中,.interp, .text, .rodata, .data, .bss等几个常用段,这里就不在进行介绍(通常.rodata,.data,和.text是挨着的,是为了节约存储空间,因为.bss不会占用存储空间)。.interp的具体实现将在以后的文章中加以描述。.note开头和.gnu开头的段基本上都是存放与调试相关的信息。
     .dynsym和.dynstr: 这两个段为动态符号段和动态字符串符号段,里面存放的是hello程序需要的外部符号信息,用于动态链接。

点击(此处)折叠或打开

  1. $readelf --dyn-syms hello

  2. Symbol table '.dynsym' contains 4 entries:
  3.    Num: Value Size Type Bind Vis Ndx Name
  4.      0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
  5.      1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
  6.      2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
  7.      3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
     .rela.dyn和.rela.plt:这两个段是重定位符号表,主要用于指明需要动态解释器(interpreter)帮忙重定位的符号。

点击(此处)折叠或打开

  1. $readelf -r hello

  2. Relocation section '.rela.dyn' at offset 0x380 contains 1 entries:
  3.   Offset Info Type Sym. Value Sym. Name + Addend
  4. 000000600ff8 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

  5. Relocation section '.rela.plt' at offset 0x398 contains 2 entries:
  6.   Offset Info Type Sym. Value Sym. Name + Addend
  7. 000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
  8. 000000601020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0
注:在Linux当中,并不是所有符号需要在启动的时候,由动态解释器(interpreter)重定位。事实上,为了加快应用程序的启动速度,Linux引入了延迟加载功能,即PLT。所谓的延迟加载是指在启动的过程中,不需要对所有符号进行重定位,只有在需要该符号的时候,才对其进行重定位,通常Linux将函数作为PLT部分。
注:其中R_X86_64_GLOB_DAT 和R_X86_64_JUMP_SLO 为重定向类型,具体参考重定向。

     .init: 与应用初始化相关,在进入main函数之前会涉及到,通常位于PLT代码的前面。

点击(此处)折叠或打开

  1. Disassembly of section .init只是一个过渡函数,由__libc_csu_init调用

  2. 00000000004003c8 <_init>:
  3.   4003c8: 48 83 ec 08 sub $0x8,%rsp
  4.   4003cc: 48 8b 05 25 0c 20 00 mov 0x200c25(%rip),%rax # 600ff8 <_DYNAMIC+0x1d0>
  5.   4003d3: 48 85 c0 test %rax,%rax
  6.   4003d6: 74 05 je 4003dd <_init+0x15>
  7.   4003d8: e8 43 00 00 00 callq 400420 <__libc_start_main@plt+0x10>
  8.   4003dd: 48 83 c4 08 add $0x8,%rsp
  9.   4003e1: c3 retq
     .plt和.plt.got: .plt用于存放PLT跳板,如puts@GLIBC_2.2.5的实现(以后讲解具体怎么跳);下图为.plt段和.got.plt段的具体内容,其中.plt段内部是跳板函数的实现(汇编语句),.got.plt则只是数据的实现:

点击(此处)折叠或打开

  1. Contents of section .got.plt:              .got.plt的内容,601020->0x400416, 601018->0x400406(标红分,为据,PLT第一次会访问这里,之后这里会被覆盖成真正的函数地址
     601000 280e6000 00000000 00000000 00000000  (.`.............
     601010 00000000 00000000 06044000 00000000  ..........@.....
     601020 16044000 00000000  

  2. Disassembly of section .plt:

  3. 00000000004003f0 <puts@plt-0x10>:   
  4.   4003f0: ff 35 12 0c 20 00 pushq 0x200c12(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  5.   4003f6: ff 25 14 0c 20 00 jmpq *0x200c14(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  6.   4003fc: 0f 1f 40 00 nopl 0x0(%rax)

  7. 0000000000400400 <puts@plt>:   这是一个跳板函数,当第一次调用的时候,GOT+0x8指向400406,然后进行函数重定位 ,第二次调用的时候,指向重定位后的地址
  8.   400400: ff 25 12 0c 20 00 jmpq *0x200c12(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  9.   400406: 68 00 00 00 00 pushq $0x0
  10.   40040b: e9 e0 ff ff ff jmpq 4003f0 <_init+0x28>

  11. 0000000000400410 <__libc_start_main@plt>:跳板函数:当第一次调用的时候,GOT+0x8指向400416,然后进行函数重定位 ,第二次调用的时候,指向重定位后的地址
  12.   400410: ff 25 0a 0c 20 00 jmpq *0x200c0a(%rip) # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
  13.   400416: 68 01 00 00 00 pushq $0x1
  14.   40041b: e9 d0 ff ff ff jmpq 4003f0 <_init+0x28>

  15. Disassembly of section .plt.got:

  16. 0000000000400420 <.plt.got>:
  17.   400420: ff 25 d2 0b 20 00 jmpq *0x200bd2(%rip) # 600ff8 <_DYNAMIC+0x1d0>
  18.   400426: 66 90 xchg %ax,%ax
    如上图,如果我调用puts函数,则是通过callq  400400 来调用的,即首先调用的是puts@plt函数,而这个函数就是在.plt段中实现的跳板函数,由它来完成最后的延迟重定向。
     .fini: 与应用退出有关,在main函数退出可能会涉及到,通常为空。
     .init_array和.fini_array: 类似于构造函数和析构函数,挂在.init_array段里面的函数,在main函数运行前运行;挂在.fini_array段里面的函数在main函数退出后运行。
     .got和.got.plt: 又名全局偏移表,用于存放全局符号地址,其中plt属于一种特殊的GOT表。.got.plt主要用于存放动态函数地址,此表和PLT搭配使用(以后会讲解)。
     .symtab和.strtab: hello程序内部能提供的符号表和一些符号信息,这个段通常用于动态库需要,应用程序对此无用。

点击(此处)折叠或打开

  1. $readelf -s hello

  2. Symbol table '.dynsym' contains 4 entries:
  3.    Num: Value Size Type Bind Vis Ndx Name
  4.      0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
  5.      1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
  6.      2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
  7.      3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

  8. Symbol table '.symtab' contains 69 entries:
  9.    Num: Value Size Type Bind Vis Ndx Name
  10.      0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
  11.      1: 0000000000400238 0 SECTION LOCAL DEFAULT 1
  12.      2: 0000000000400254 0 SECTION LOCAL DEFAULT 2
  13.      3: 0000000000400274 0 SECTION LOCAL DEFAULT 3
  14.      4: 0000000000400298 0 SECTION LOCAL DEFAULT 4
  15.      5: 00000000004002b8 0 SECTION LOCAL DEFAULT 5
  16.                   限于篇幅,此处省略部分符号
  17.     55: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC
  18.     56: 0000000000601028     0 NOTYPE  GLOBAL DEFAULT   25 __data_start
  19.     57: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
  20.     58: 0000000000601030     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle
  21.     59: 00000000004005f0     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
  22.     60: 0000000000400570   101 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
  23.     61: 0000000000601040     0 NOTYPE  GLOBAL DEFAULT   26 _end
  24.     62: 0000000000400430    42 FUNC    GLOBAL DEFAULT   14 _start
  25.     63: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   26 __bss_start
  26.     64: 0000000000400548    32 FUNC    GLOBAL DEFAULT   14 main
  27.     65: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
  28.     66: 0000000000601038     0 OBJECT  GLOBAL HIDDEN    25 __TMC_END__
  29.     67: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
  30.     68: 00000000004003c8     0 FUNC    GLOBAL DEFAULT   11 _init                  
    如上图,符号表可以看出一个符号是否为全局符号,是否为弱符号,是否为局部符号,符号是函数还是变量等等。其中UND表示未定义,需要外部重定位的,GLOBAL为全局,LOCAL为局部,WEAK为弱符号,FUNC为函数,OBJECT为变量,NOTYPE为需要外部重定位的。例如:
64行:64: 0000000000400548    32 FUNC    GLOBAL DEFAULT   14 main
函数名字main函数,全局符号,函数,地址0x400548等。
    另外,我们可以通过objdump -s hello获取整个hello文件各个section对应的内容,如下:

点击(此处)折叠或打开

  1. hello: file format elf64-x86-64 (下面的布局是按照program header提供的虚拟内存地址布局的,如.interp的起始地址0x400238

  2. Contents of section .interp:
  3.  400238 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
  4.  400248 7838362d 36342e73 6f2e3200 x86-64.so.2.
  5. Contents of section .note.ABI-tag:
  6.  400254 04000000 10000000 01000000 474e5500 ............GNU.
  7.  400264 00000000 02000000 06000000 20000000 ............ ...
  8. Contents of section .note.gnu.build-id:
  9.  400274 04000000 14000000 03000000 474e5500 ............GNU.
  10.  400284 ce3c4f78 e2194357 f5296b53 6f39b5c2 .<Ox..CW.)kSo9..
  11.  400294 e4f14ee6 ..N.
  12. Contents of section .gnu.hash:
  13.  400298 01000000 01000000 01000000 00000000 ................
  14.  4002a8 00000000 00000000 00000000 ............
  15. Contents of section .dynsym:
  16.  4002b8 00000000 00000000 00000000 00000000 ................
  17.  4002c8 00000000 00000000 0b000000 12000000 ................
  18.  4002d8 00000000 00000000 00000000 00000000 ................
  19.  4002e8 10000000 12000000 00000000 00000000 ................
  20.  4002f8 00000000 00000000 22000000 20000000 ........"... ...
  21.  400308 00000000 00000000 00000000 00000000 ................
  22. Contents of section .dynstr:
  23.  400318 006c6962 632e736f 2e360070 75747300 .libc.so.6.puts.
  24.  400328 5f5f6c69 62635f73 74617274 5f6d6169 __libc_start_mai
  25.  400338 6e005f5f 676d6f6e 5f737461 72745f5f n.__gmon_start__
  26.  400348 00474c49 42435f32 2e322e35 00 .GLIBC_2.2.5.
  27. Contents of section .gnu.version:
  28.  400356 00000200 02000000 ........
  29. Contents of section .gnu.version_r:
  30.  400360 01000100 01000000 10000000 00000000 ................
  31.  400370 751a6909 00000200 31000000 00000000 u.i.....1.......
  32. Contents of section .rela.dyn:
  33.  400380 f80f6000 00000000 06000000 03000000 ..`.............
  34.  400390 00000000 00000000 ........
  35. Contents of section .rela.plt:
  36.  400398 18106000 00000000 07000000 01000000 ..`.............
  37.  4003a8 00000000 00000000 20106000 00000000 ........ .`.....
  38.  4003b8 07000000 02000000 00000000 00000000 ................
  39. Contents of section .init:
  40.  4003c8 4883ec08 488b0525 0c200048 85c07405 H...H..%. .H..t.
  41.  4003d8 e8430000 004883c4 08c3 .C...H....
  42. Contents of section .plt:
  43.  4003f0 ff35120c 2000ff25 140c2000 0f1f4000 .5.. ..%.. ...@.
  44.  400400 ff25120c 20006800 000000e9 e0ffffff .%.. .h.........
  45.  400410 ff250a0c 20006801 000000e9 d0ffffff .%.. .h.........
  46. Contents of section .plt.got:
  47.  400420 ff25d20b 20006690 .%.. .f.
  48. Contents of section .text:
  49.       省略.text的具体内容
  50. Contents of section .fini:
  51.  4005e4 4883ec08 4883c408 c3 H...H....
  52. Contents of section .rodata:
  53.  4005f0 01000200 4265666f 7265206d 61696e00 ....Before main.
  54.  400600 41667465 72206d61 696e0048 656c6c6f After main.Hello
  55.  400610 20576f72 6c6400 World.
  56. Contents of section .eh_frame_hdr:
  57.  400618 011b033b 44000000 07000000 d8fdffff ...;D...........
  58.  400628 90000000 18feffff 60000000 0effffff ........`.......
  59.  400638 b8000000 1fffffff d8000000 30ffffff ............0...
  60.  400648 f8000000 58ffffff 18010000 c8ffffff ....X...........
  61.  400658 60010000 `...
  62. Contents of section .eh_frame:
  63.  400660 14000000 00000000 017a5200 01781001 .........zR..x..
  64.  400670 1b0c0708 90010710 14000000 1c000000 ................
  65.  400680 b0fdffff 2a000000 00000000 00000000 ....*...........
  66.  400690 14000000 00000000 017a5200 01781001 .........zR..x..
  67.  4006a0 1b0c0708 90010000 24000000 1c000000 ........$.......
  68.  4006b0 40fdffff 30000000 000e1046 0e184a0f @...0......F..J.
  69.  4006c0 0b770880 003f1a3b 2a332422 00000000 .w...?.;*3$"....
  70.  4006d0 1c000000 44000000 4efeffff 11000000 ....D...N.......
  71.  4006e0 00410e10 8602430d 064c0c07 08000000 .A....C..L......
  72.  4006f0 1c000000 64000000 3ffeffff 11000000 ....d...?.......
  73.  400700 00410e10 8602430d 064c0c07 08000000 .A....C..L......
  74.  400710 1c000000 84000000 30feffff 20000000 ........0... ...
  75.  400720 00410e10 8602430d 065b0c07 08000000 .A....C..[......
  76.  400730 44000000 a4000000 38feffff 65000000 D.......8...e...
  77.  400740 00420e10 8f02420e 188e0345 0e208d04 .B....B....E. ..
  78.  400750 420e288c 05480e30 8606480e 3883074d B.(..H.0..H.8..M
  79.  400760 0e40720e 38410e30 410e2842 0e20420e .@r.8A.0A.(B. B.
  80.  400770 18420e10 420e0800 14000000 ec000000 .B..B...........
  81.  400780 60feffff 02000000 00000000 00000000 `...............
  82.  400790 00000000 ....
  83. Contents of section .init_array:
  84.  600e00 00054000 00000000 26054000 00000000 ..@.....&.@.....
  85. Contents of section .fini_array:
  86.  600e10 e0044000 00000000 37054000 00000000 ..@.....7.@.....
  87. Contents of section .jcr:
  88.  600e20 00000000 00000000 ........
  89. Contents of section .dynamic:
  90.          省略.dynamic具体内容
  91. Contents of section .got:
  92.  600ff8 00000000 00000000 ........
  93. Contents of section .got.plt:
  94.  601000 280e6000 00000000 00000000 00000000 (.`.............
  95.  601010 00000000 00000000 06044000 00000000 ..........@.....
  96.  601020 16044000 00000000 ..@.....
  97. Contents of section .data:
  98.  601028 00000000 00000000 00000000 00000000 ................
  99. Contents of section .comment:
  100.  0000 4743433a 20285562 756e7475 20352e34 GCC: (Ubuntu 5.4
  101.  0010 2e302d36 7562756e 7475317e 31362e30 .0-6ubuntu1~16.0
  102.  0020 342e3131 2920352e 342e3020 32303136 4.11) 5.4.0 2016
  103.  0030 30363039 00 0609.
    通过上图,再结合各个段的具体信息,可以做进一步分析。上图的具体格式为:
Contents of section 段名:
    地址  内容1   内容2 内容3 内容4      ASCII字符
    地址  内容1   内容2 内容3 内容4      ASCII字符
    地址  内容1   内容2 内容3 内容4      ASCII字符
    ...........................

elf文件的大致粗略信息就是如此,如果有需要可以进行更详细的分析,这篇到这里为止,下一篇,主要分析execve系统调用里面到底完成了什么。

阅读(395) | 评论(0) | 转发(0) |
0

上一篇:Linux应用程序 启动流程

下一篇:没有了

给主人留下些什么吧!~~