ELF文件实例分析

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    
















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值