ELF(Executable and Linkable Format)是Unix及类Unix系统下可执行文件、共享库等二进制文件标准格式。
ELF文件结构:
(1) ELF header
(2) Program header table,对应于segments
(3) Section header table,对应于sections
(4) 被Program header table或Sectionheader table指向的内容
segments与sections的关系:
(1) 每个segments可以包含多个sections
(2) 每个sections可以属于多个segments
(3) segments之间可以有重合的部分
下图是readelf工具输出的某ELF文件segments与sections信息:
可以看到,segments部分包含各segments的地址、偏移、属性等;而sections部分则依次列出每个segment所包含的sections。注意到,sections通常为全小写字母,而segments通常为全大写字母。
此外,这两者之间另一个关键不同点是,sections包含的是链接时需要的信息,而segments包含运行时需要的信息。即,在链接时,链接器通过section header table去寻找sections;在运行时,加载器通过program header table去寻找segments。可见下图:
比较重要的sections:
(1) .init_array: 动态库加载或可执行文件开始执行前调用的函数列表
(2) .text: 代码
(3) .got: Global offset table(GOT),包含加载时需要重定位的变量的地址
(4) .got.plt: 包含动态库中函数地址的GOT
比较重要的segments:
(1) LOAD: 运行时需要被加载进内存的segment
(2) GNU_STACK: 决定运行时栈是否可执行
(3) DYNAMIC: 动态链接信息,对应于.dynamicsection
#include <stdio.h>
#include <windows.h>
//VS2015以上需要添加libucrtd.lib文件到工程目录下
#pragma comment(lib,"libucrtd.lib")
typedef unsigned short __u16;
typedef int __s32;
typedef unsigned int __u32;
typedef __u32 Elf32_Addr;
typedef __u16 Elf32_Half;
typedef __u32 Elf32_Off;
typedef __s32 Elf32_Sword;
typedef __u32 Elf32_Word;
#define EI_NIDENT 16
typedef struct elf32_hdr{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf32_phdr{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
int main(int argc, char* argv[])
{
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hMap = NULL;
LPVOID pFile = NULL;
hFile = CreateFile("F:\\Workspace\\a.out",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_ARCHIVE,
0);
if(hFile==INVALID_HANDLE_VALUE)
{
printf("OpenFile Error,Code:%d\n",GetLastError());
return 0;
}
hMap = CreateFileMapping(hFile,NULL,PAGE_READWRITE,NULL,NULL,NULL);
if(hMap == NULL)
{
printf("CreateFileMapping Error,Code:%d\n",GetLastError());
CloseHandle(hFile);
return 0;
}
pFile = MapViewOfFile(hMap,FILE_MAP_READ|FILE_MAP_WRITE,NULL,NULL,NULL);
if(pFile == NULL)
{
printf("MapViewOfFile Error,Code:%d\n",GetLastError());
CloseHandle(hMap);
CloseHandle(hFile);
return 0;
}
Elf32_Ehdr* p_Elf32_Ehdr = (Elf32_Ehdr*)pFile;
Elf32_Phdr* p_Elf32_Phdr = (Elf32_Phdr*)((char*)pFile + p_Elf32_Ehdr->e_phoff);
{
Elf32_Phdr *tmp = p_Elf32_Phdr;
for (int i=0; i<p_Elf32_Ehdr->e_phnum; i++,tmp++)
{
printf("%d off:%#10x filesize:%#10x memsize:%#10x\n",
i,
tmp->p_offset,
tmp->p_filesz,
tmp->p_memsz);
}
}
printf("\n");
Elf32_Shdr* p_Elf32_Shdr = (Elf32_Shdr*)((char*)pFile + p_Elf32_Ehdr->e_shoff);
char *objsn = (char*)((char*)pFile + p_Elf32_Shdr[p_Elf32_Ehdr->e_shstrndx].sh_offset);
{
Elf32_Shdr *tmp = p_Elf32_Shdr;
for (int i=0; i<p_Elf32_Ehdr->e_shnum; i++,tmp++)
{
printf("%d off:%#10x size:%#10x entsize:%#10x %s\n",
i,tmp->sh_offset,
tmp->sh_size,
tmp->sh_entsize,
objsn + tmp->sh_name);
}
}
printf("\nenter:%#10x \n",p_Elf32_Ehdr->e_entry);
UnmapViewOfFile(pFile);
CloseHandle(hMap);
CloseHandle(hFile);
return 0;
}
本文只做学习之用