简单的Elf解析器实现

  摘要:之前虽然了解过ELF文件的具体格式,但是对改文件的理解还是存在一些不足,因此本文尝试写了一个简单的ELF解析器对ELF文件进行解析并输出Header,Program Header Table和Section Header Table。
  关键字:C++,ELF
  读者注意:阅读本文是你需要对ELF有最基本的了解。

  源码链接

1 准备工作

  在进行文件解析之前当然需要将Linux的ELF头文件引入过来,但是需要注意的该文件依赖Linux内部的一些头文件,所以我们需要将上面include的头文件删除,并重新定义对应的类型。没必要把依赖的头文件全部引入到我们的工程。

typedef uint32_t __u32;
typedef uint16_t __u16;
typedef uint64_t __u64;
typedef  int32_t __s32;
typedef  int16_t __s16;
typedef  int64_t __s64;

2 解析

  解析的过程比较简单就是读文件然后将对应的内存转换为目标结构体即可一步一步解析,过程比较简单只是比较累人。
  在进行解析前需要注意因为我们可能是在Windows上解析另一台Linux或者其他机器编译的可执行文件或者二进制文件,我们无法确认改文件的具体位数和大小端。因此我们需要先将ELF中的EIDENT魔数读取出来,根据该数值来判断具体的文件位数和大小端。

Error ElfParser::identity() {
	unsigned char ident[EI_NIDENT]{};
	int readlen{};
	if (Error::None != readbuf(ident, sizeof(unsigned char) * EI_NIDENT)) {
		return Error::IO;
	}

	if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) {
		printf("the first fource byte is not 0x7f E L f but %x %c %c %c\n", ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3]);
		return Error::INVALID_DATA;
	}

	_bit = static_cast<FileBit>(ident[4]);
	_order = static_cast<BitOrder>(ident[5]);
	resetio();
	return Error::None;
}

  如果该文件的存储顺序和本地机器不同就需要将数据进行转换,比如大端转小端,小端转大端。比如下面将ELFHeader的每个成员的顺序都进行转换。

template<class T>
T swapEndian(const T v) {
	static_assert(CHAR_BIT == 8, "char_bit is not 8");
	union{
		T u;
		unsigned char u8[sizeof(T)];
	}src, dst;
	src.u = v;
	for (int i = 0; i < sizeof(T); i++) {
		dst.u8[i] = src.u8[sizeof(T) - i - 1];
	}

	return dst.u;
}

void Elf64::parseHeader(unsigned char *ptr) {
	_header = *(elf64_hdr*)ptr;
	if (_order == nativeMachineOrder()) {
		return;
	}

	swapEndian(_header.e_type);
	swapEndian(_header.e_machine);
	swapEndian(_header.e_version);
	swapEndian(_header.e_entry);
	swapEndian(_header.e_phoff);
	swapEndian(_header.e_shoff);
	swapEndian(_header.e_flags);
	swapEndian(_header.e_ehsize);
	swapEndian(_header.e_phentsize);
	swapEndian(_header.e_phnum);
	swapEndian(_header.e_shentsize);
	swapEndian(_header.e_shnum);
	swapEndian(_header.e_shstrndx);
}

  从内存中拿到ELF文件的结构体后,如果需要将ELF的数据转换为可读的形式,需要一一对着标准文档来进行解析,按照自己觉得舒适的方式转换为字符串输出即可。过程比较简单,但是真的很费时间,因为东西比较多。

3 结果

下面是readelf的输出:

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x10c0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          15336 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30

  下面是本文实现的解析器的输出(有些字段可能是Unknown之类,因为字段太多了,我偷了个懒,比如Machine是x86_64,该字段有100个选项,太多了我只写了10个,后面的都是Unknown):

Elf Header:
    Magic Number:                      0x7f 0x45 0x4c 0x46 0x2 0x1 0x1 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    File Identity:                     ELF
    Arch Bit:                          64bit
    Arch Bit Order:                    LSB
    Version:                           1
    OSAbi:                             None
    Type:                              Shared object file
    Machine:                           Unknown
    Version:                           Current Version
    Entry Point:                       0x10c0
    Program Hedaer Table Offset:       64
    Section Hedaer Table Offset:       15336
    Flags:                             0x0
    Header Size:                       64(in bytes)
    Program Hedaer Size:               56(in bytes)
    Program Header Number:             13
    Section Hedaer Size:               64(in bytes)
    Section Header Number:             31
    String Table Seciton Index:        30

Segment Header
    Type        Offset      VirtAddr          PhyAddr           FileSz      MemSz       Flags       Align
    PT_PHDR     64          0x40              0x40              728         728         4           8
    PT_INTERP   792         0x318             0x318             28          28          4           1
    PT_LOAD     0           0x0               0x0               2112        2112        4           4096
    PT_LOAD     4096        0x1000            0x1000            725         725         5           4096
    PT_LOAD     8192        0x2000            0x2000            432         432         4           4096
    PT_LOAD     11640       0x3d78            0x3d78            664         992         6           4096
    PT_DYNAMIC  11664       0x3d90            0x3d90            512         512         6           8
    PT_NOTE     824         0x338             0x338             32          32          4           8
    PT_NOTE     856         0x358             0x358             68          68          4           4
    PT_INTERP   824         0x338             0x338             32          32          4           8
    PT_NULL     8212        0x2014            0x2014            84          84          4           4
    PT_LOAD     0           0x0               0x0               0           0           6           16
    PT_DYNAMIC  11640       0x3d78            0x3d78            648         648         4           1

Section Header
    Name                Type            Address Offset  Size    Entsize Flags   Link    Info    Align
                        SHT_NULL        0x0     0       0       0       0       0       0       0
    .interp             SHT_PROGBITS    0x318   792     28      0       2       0       0       1
    .note.gnu.property  SHT_NOTE        0x338   824     32      0       2       0       0       8
    .note.gnu.build-id  SHT_NOTE        0x358   856     36      0       2       0       0       4
    .note.ABI-tag       SHT_NOTE        0x37c   892     32      0       2       0       0       4
    .gnu.hash           SHT_SYMTAB      0x3a0   928     40      0       2       6       0       8
    .dynsym             SHT_DYNSYM      0x3c8   968     312     24      2       7       1       8
    .dynstr             SHT_STRTAB      0x500   1280    355     0       2       0       0       1
    .gnu.version        SHT_DYNSYM      0x664   1636    26      2       2       6       0       2
    .gnu.version_r      SHT_SHLIB       0x680   1664    64      0       2       7       2       8
    .rela.dyn           SHT_RELA        0x6c0   1728    288     24      2       6       0       8
    .rela.plt           SHT_RELA        0x7e0   2016    96      24      66      6       24      8
    .init               SHT_PROGBITS    0x1000  4096    27      0       6       0       0       4
    .plt                SHT_PROGBITS    0x1020  4128    80      16      6       0       0       16
    .plt.got            SHT_PROGBITS    0x1070  4208    16      16      6       0       0       16
    .plt.sec            SHT_PROGBITS    0x1080  4224    64      16      6       0       0       16
    .text               SHT_PROGBITS    0x10c0  4288    517     0       6       0       0       16
    .fini               SHT_PROGBITS    0x12c8  4808    13      0       6       0       0       4
    .rodata             SHT_PROGBITS    0x2000  8192    17      0       2       0       0       4
    .eh_frame_hdr       SHT_PROGBITS    0x2014  8212    84      0       2       0       0       4
    .eh_frame           SHT_PROGBITS    0x2068  8296    328     0       2       0       0       8
    .init_array         SHT_INIT_ARRAY  0x3d78  11640   16      8       3       0       0       8
    .fini_array         SHT_FINI_ARRAY  0x3d88  11656   8       8       3       0       0       8
    .dynamic            SHT_DYNAMIC     0x3d90  11664   512     16      3       7       0       8
    .got                SHT_PROGBITS    0x3f90  12176   112     8       3       0       0       8
    .data               SHT_PROGBITS    0x4000  12288   16      0       3       0       0       8
    .bss                SHT_NOBITS      0x4040  12304   280     0       3       0       0       64
    .comment            SHT_PROGBITS    0x0     12304   43      1       48      0       0       1
    .symtab             SHT_SYMTAB      0x0     12352   1800    24      0       29      50      8
    .strtab             SHT_STRTAB      0x0     14152   897     0       0       0       0       1
    .shstrtab           SHT_STRTAB      0x0     15049   282     0       0       0       0       1

你可能感兴趣的:(linux,逆向,c++,linux)