《Linux及安全》实践3.1

时间:2024-08-25 17:34:02

《Linux及安全》实践三 ELF格式文件分析

一、基础操作

1.查看大小端、32还是64

  • 《Linux及安全》实践3.1

  • 《Linux及安全》实践3.1

  • 《Linux及安全》实践3.1

  • 由此可以看出,本人实践所用到的是32位Ubuntu,数据存储采用小端法。

2.编写hello.c文件

  • 《Linux及安全》实践3.1

3.查看文件类型、大小

  • 《Linux及安全》实践3.1

  • 可以看到是可重定位文件,大小为1028比特

4.以16进制形式输出hello.o文件

  • 《Linux及安全》实践3.1

5.通过ELF headers table阅读文件各个段的信息

  • 《Linux及安全》实践3.1

  • 《Linux及安全》实践3.1

  • 《Linux及安全》实践3.1

  • 可以看到,Size of this header(文件头部)52bytes

二、ELF文件格式分析

1.查看ELF头部定义

  • ELF头部的定义在/usr/include/elf.h中:
    • 《Linux及安全》实践3.1

        - (为不同位数设置)
    • 《Linux及安全》实践3.1

        - (ELF头结构体定义)

2.分析hello 的ELF头部

  • 已知头部大小52字节
    • 《Linux及安全》实践3.1

        0000000 457f 464c 0101 0001 0000 0000 0000 0000
      0000010 0002 0003 0001 0000 8320 0804 0034 0000
      0000020 1174 0000 0000 0000 0034 0020 0009 0028
      0000030 001e 001b
    • 第一行分析:

      • 其前16个字节(第一行,对应e_ident[EI_NIDENT])实际表示内容为7f45 4c46 0101 0100 0000 0000 0000 0000,前四个字节7f454c46(0x45,0x4c,0x46是'e','l','f'对应的ascii编码)是一个魔数(magic number),表示这是一个ELF对象。接下来的一个字节01表示是一个32位对象,接下来的一个字节01表示是小端法表示,再接下来的一个字节01表示文件头版本。剩下的默认都设置为0。
    • 第二行分析:

      • e_type(两个字节)值为0x0002,表示可执行文件。
      • e_machine(两个字节)值为0x0003,表示是intel80386处理器体系结构。
      • e_version(四个字节)值为0x00000001,表示是当前版本。
      • e_entry(四个字节)值为0x83200804,表示程序进入点。
      • e_phoff(四个字节)值为0x00340000,表示结头表偏移量。
    • 第三行分析:

      • e_shoff(四个字节)值为0x1174,表示段表的偏移地址。
      • e_flags(四个字节)值为0x00000000,表示未知处理器特定标志(#define EF_SH_UNKNOWN 0x0)。
      • e_ehsize(两个字节)值为0034,表示elf文件头大小(正好是52个字节)。
      • e_phentsize(两个字节)为0x0020,表示程序头表中每个条目的大小为32.
      • e_ehentsize(两个字节)值为0x0028表示段头大小为40个字节。
      • e_shnum(两个字节)值为0x001e,表示段表入口有28个。e_shstrndx(两个字节)值为0x001b,表示段名串表的在段表中的索引号为27。

3.分析hello.o的section header table

  • 《Linux及安全》实践3.1

  • 《Linux及安全》实践3.1

  • 由上图可见,section header table中包括了各段的偏移地址(off)和大小(size),可以由此找到各段的位置。

4.分析各段

  1. .text段分析

    • Hello.o中.text大小为0X1c,即十进制的28。
    • 对hello.o进行反汇编
      • 《Linux及安全》实践3.1

      • 可以看到.text段跨越0x0到0x1b,恰好共0x1c(即28)个字节

  2. .strtab段分析

    • 《Linux及安全》实践3.1

    • 该段的offset是0x3d8(正好在.symtab段之后),size是0x13,即到0x2ea为止。

      对应字符串为:“\0hello.c\0main\0puts\0”

  3. .symtab段分析

    • 《Linux及安全》实践3.1

    • 《Linux及安全》实践3.1

      • 上图是.symtab所拥有的入口数量
    • 《Linux及安全》实践3.1

    • 从上面的分析已经知道,.symtab的偏移量为0x328(即808),大小为0xb0(即十进制176)。因而数据即上图中标为黄色的部分

    • 《Linux及安全》实践3.1

    • 该结构大小为16个字节,而整个符号表段大小为176个字节,所以总共可以分成11个符号。

    • 《Linux及安全》实践3.1

    • 这11个符号刚好和前面objdump输出的符号表(10个符号,第一个符号为空,所以被忽略)结果相对应;也和使用readelf中符号表相关内容对应(readelf命令输出结果比objdump输出结果看起来更易懂一些):

  4. rodata段分析

    • 《Linux及安全》实践3.1

    • 因为位于.rodata段上面的.bss段size为0x00,所以.bss和.rodata偏移量一样(都是0x50),.rodata段大小为0xd,也就是13个字节。即:

      68 65 6c 6c 6f 20 2c 20 35 32 31 36 00。

    • 《Linux及安全》实践3.1

    • 《Linux及安全》实践3.1

    • 《Linux及安全》实践3.1

    • 《Linux及安全》实践3.1

      • 对照ACII码表 ,可以拼出其正好对应HELLO,5216

5.补充

  • 从前面对ELF头的解析可以知道段表的地址是从0x1174(e_shoff项)开始,而上面的.shstrtab的开始地址为0xc0,大小为0x5f,所以此处段表应该是从0x11f开始(0xc0+0x5f)。再根据e_shnum=23和ehentsize=28可知,有23个段,每个段占28个字节大小,总共占据644个字节(16进制为0x284)。段入口的类型定义如下(/usr/include/elf.h):

  • 《Linux及安全》实践3.1

    • 从0x1174开始有13个段,每个段占28个字节大小。
  • 第一个段,其中内容全部为0,所以不表示任何段。内容如下:

    • 《Linux及安全》实践3.1
  • 第二个段对应内容为:

    • 《Linux及安全》实践3.1

    • 段中每个成员均为4个字节,所以分析起来相对简单一些。

    • sh_name值为0x0000001f,它表示该段名称在.shstrtab中偏移量,通过计算可知该名称为.text。

    • sh_type值为0x00000001(对应SHT_PROGBITS),表示这个段拥有程序所定义的信息,其格式和含义完全有该程序确定。

    • sh_flags值为0x00000006(对应于SHF_ALLOC和SHF_EXECINSTR)。

    • sh_addr值为0x00000000,表示这个段不会出现在进程的地址镜像中。

    • sh_offset值为0x00000034(偏移地址),

    • sh_size值为0x00000017,表示代码段大小为23(0x17)个字节。

    • sh_link值为0x00000000,表示没有链接信息。

    • sh_info值为0x00000000,表示没有辅助信息。

    • sh_addalign值为0x00000004,表示4个字节对齐

    • sh_entsize值为0x00000000,表示没有入口。

  • 第三个段为:

    • 《Linux及安全》实践3.1

    • 该段为.rel.text段(偏移量为0x0000001b),sh_type为0x00000009(对应SHT_REL),sh_offset为0x000003ec,sh_size为0x00000010(16个字节)。sh_link和sh_info分别为b和1,分别表示相关符号表索引和重定位应用段的段头索引。其余段的内容不再详细分析,可以自己分析并于前面readelf输出结果相对照。

      ……

  • 第23个段

    • 《Linux及安全》实践3.1