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
#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
相关文章推荐
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析
- linux中ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载
- ELF可执行格式文件实例分析
- Intel平台下linux中 ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析(一):
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析(一): 加载
- 实例分析ELF文件动态链接
- Intel平台下linux中ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载
- elf文件格式实例分析
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析
- Intel平台下linux中ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载
- Intel平台下Linux中 ELF文件动态链接的加载、解析及实例分析(一): 加载
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析(一): 加载
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析
- Intel平台下linux中 ELF文件动态链接的加载、解析及实例分析(二): 函数解析与卸载
- Intel平台下Linux中 ELF文件动态链接的加载、解析及实例分析(一): 加载
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析(一): 加载