您的位置:首页 > 其它

ELF文件实例分析

2010-04-12 22:53 351 查看
1.实例代码如下所示:

#include <elf.h>

int foo1()

{

printf("[+] foo1 addr:%p/n",foo1);

foo2();

}

int foo2()

{

printf("[+] foo2 addr:%p/n",foo2);

foo3();

}

int foo3()

{

printf("[+] foo3 addr:%p/n",foo3);

foo4();

}

int foo4()

{

printf("[+] foo4 addr:%p/n",foo4);

}

main()

{

foo1();

}

2.elf文件的开头是一个Ehdr的结构. 该结构定义在/usr/include/elf.h中, 我们看看该结构:

typedef struct

{

unsigned char    e_ident[EI_NIDENT];    /* Magic number and other info */

Elf32_Half    e_type;            /* 目标文件类型 */

Elf32_Half    e_machine;        /* Architecture */

Elf32_Word    e_version;        /* Object file version */

Elf32_Addr    e_entry;        /* 入口地址 */

Elf32_Off    e_phoff;        /* Program header table文件偏移 */

Elf32_Off    e_shoff;        /* Section header table 文件偏移 */

Elf32_Word    e_flags;        /* Processor-specific flags */

Elf32_Half    e_ehsize;        /* ELF header 大小 */

Elf32_Half    e_phentsize;        /* 每个Program header大小 */

Elf32_Half    e_phnum;        /* 一共多少个Program header */

Elf32_Half    e_shentsize;        /* 每个Section header大小 */

Elf32_Half    e_shnum;        /* 一共多少个 Section header */

Elf32_Half    e_shstrndx;        /* Section的字符表在section header table的索引值 */

} Elf32_Ehdr;

除了Elf32_Half是2个字节(16位)外, 其他变量定义等都是4个字节(32位).

从上面的结构可以看出来sizeof(Elf32_Ehdr)=13*4=0x34

我们来看看文件elf8头52字节的内容:

[root@localhost test]# hexdump -s 0 -n 52 -C func

00000000  7f 45 4c 46 01 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|

00000010  02 00 03 00 01 00 00 00  10 83 04 08 34 00 00 00  |............4...|

00000020  e8 08 00 00 00 00 00 00  34 00 20 00 08 00 28 00  |........4. ...(.|

00000030  1e 00 1b 00                                       |....|

00000034

我们对照这个结构一个个来分析:

e_ident[EI_NIDENT]: 16字节: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00

ELFMAG0 0x7f e_ident[0]

ELFMAG1 'E' e_ident[1]

ELFMAG2 'L' e_ident[2]

ELFMAG3 'F' e_ident[3]

ELFCLASS32 1 e_ident[4]

ELFDATA2LSB 1 e_ident[5]

EI_VERSION 1 e_ident[6]

剩下的全为0

e_type:2字节: 02 00 表示可执行文件(ET_EXEC 2 Executable file)

e_machine: 2字节: 03 00 表示386体系文件(EM_386 3 Intel 80386)

e_version: 4字节: 01 00 00 00 和e_ident里面的EI_VERSION含义一样.

e_entry: 4字节: 10 83 04 08 表示程序入口地址0x08048310

e_phoff: 4字节: 34 00 00 00 表示program head table在文件中的偏移量(开始位置)

e_shoff: 4字节: e8 08 00 00 表示section head table在文件中的偏移量(开始位置)

e_flags: 4字节: 00 00 00 00

e_ehsize: 2字节: 34 00 表示elf header大小, 其实就是sizeof(Elf32_Ehdr)

e_phentsize: 2字节: 20 00 表示每个program header 的大小(0x20)

e_phnum: 2字节: 08 00 表示一共多少个program header(0x06)

e_shentsize: 2字节: 28 00 表示每个section header的大小(0x28)

e_shnum: 2字节: 1e 00, 表示有多少个section header

e_shstrndx: 2字节: 1b 00 表示section string table在section header table中的索引值.(即第几个section描述了section string table的位置和大小)

看看readelf的分析结果:

[root@localhost test]# readelf -h func

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:          2280 (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:         30

  Section header string table index: 27

program header

除了开始的elf header位置是固定的外, 其他位置都是相关联的, 或者说都是要到elf header里面读取的.

看elf.h里面关于这个结构的定义:

typedef struct

{

Elf32_Word    p_type;            /* Segment type */

Elf32_Off    p_offset;        /* Segment file offset */

Elf32_Addr    p_vaddr;        /* Segment virtual address */

Elf32_Addr    p_paddr;        /* Segment physical address */

Elf32_Word    p_filesz;        /* Segment size in file */

Elf32_Word    p_memsz;        /* Segment size in memory */

Elf32_Word    p_flags;        /* Segment flags */

Elf32_Word    p_align;        /* Segment alignment */

} Elf32_Phdr;

我们来计算一下这个结构的大小, sizeof(Elf32_Phdr)=0x20, 从前面的elf header信息我们也同样可以知道这个长度是0x20, elf文件中一共有8个这样的Phdr, 最开始的一个Phdr在文件的0x34偏移处. 我们可以这样读取:

[root@localhost test]# hexdump -s 52 -n 32 -C func

00000034  06 00 00 00 34 00 00 00  34 80 04 08 34 80 04 08  |....4...4...4...|

00000044  00 01 00 00 00 01 00 00  05 00 00 00 04 00 00 00  |................|

00000054

按结构进行分析:

p_type: 4字节: 06 00 00 00, 表示该段是PT_PHDR类型(自己的入口)

p_offset: 4字节: 34 00 00 00 在文件中的偏移量.

p_vaddr: 4字节: 34 80 04 08 虚拟地址:0x08048034

p_paddr: 4字节: 34 80 04 08 物理地址: 0x08048034

p_filesz: 4字节: 00 01 00 00 段的大小:0x100

p_memsz: 4字节: c0 00 00 00 在内存中的大小: 0x100

p_flags: 4字节: 05 00 00 00 段标记

p_align: 4字节: 04 00 00 00

我们来看一看PT_INTERP段的信息:

[root@localhost test]# hexdump -s 84 -n 32 -C func

00000054  03 00 00 00 34 01 00 00  34 81 04 08 34 81 04 08  |....4...4...4...|

00000064  13 00 00 00 13 00 00 00  04 00 00 00 01 00 00 00  |................|

00000074

这个segment指出了程序依赖解释器的路径/文件名, 定义在0x0134的偏移量处, 大小是0x13字节

[root@localhost test]# hexdump -s 0x134 -n 19 -C func

00000134  2f 6c 69 62 2f 6c 64 2d  6c 69 6e 75 78 2e 73 6f  |/lib/ld-linux.so|

00000144  2e 32 00                                          |.2.|

00000147

该elf文件依赖/lib/ld-linux.so.2来解释.

我们可以用readelf来检测看看:

[root@localhost test]# readelf -l func

Elf file type is EXEC (Executable file)

Entry point 0x8048310

There are 8 program headers, starting at offset 52

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 0x005e0 0x005e0 R E 0x1000

  LOAD           0x0005e0 0x080495e0 0x080495e0 0x000fc 0x00104 RW  0x1000

  DYNAMIC        0x0005f4 0x080495f4 0x080495f4 0x000c8 0x000c8 RW  0x4

  NOTE           0x000148 0x08048148 0x08048148 0x00044 0x00044 R   0x4

  GNU_EH_FRAME   0x00056c 0x0804856c 0x0804856c 0x0001c 0x0001c R   0x4

  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

 Section to Segment mapping:

  Segment Sections...

   00    

   01     .interp

   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame

   03     .ctors .dtors .jcr .dynamic .got .got.plt .data .bss

   04     .dynamic

   05     .note.ABI-tag .note.gnu.build-id

   06     .eh_frame_hdr

   07    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐