编程读取ELF文件头

    一个C语言源程序(.c文件)经过汇编以后生成目标文件(.o文件),目标文件再经过链接生成可执行文件。在linux系统中,目标文件和可执行文件都是ELF格式的,了解ELF文件的结构对于理解程序的编译、链接和装载运行至关重要。ELF文件的格式如下图所示,以文件头(ELF Header)开始,后面跟着代码段(.text)、数据段(.data)等。

 

ELF Header

.text

.data

.bss

.rodata

Other sections

Section header table

String Tables

Symbol Tables

 

    文件头中保存着文件的基本属性,要解析整个ELF文件,必须从文件头开始。下面自己编写一个小程序来读取ELF文件头,它的功能等价于Linux提供的命令readelf  -h  xxx.o。自己写代码实现这些命令能加深对ELF文件结构的理解。

 

    ELF文件头的结构定义在/usr/include/elf.h文件中,分32位和64位两种:

32位:

typedef struct

{

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

    Elf32_Half        e_type;                  /* Object file type */

    Elf32_Half        e_machine;               /* Architecture */

    Elf32_Word        e_version;               /* Object file version */

    Elf32_Addr        e_entry;                 /* Entry point virtual address */

    Elf32_Off         e_phoff;                 /* Program header table file offset */

    Elf32_Off         e_shoff;                 /* Section header table file offset */

    Elf32_Word        e_flags;                 /* Processor-specific flags */

    Elf32_Half        e_ehsize;                /* ELF header size in bytes */

    Elf32_Half        e_phentsize;             /* Program header table entry size*/

    Elf32_Half        e_phnum;                 /* Program header table entrycount */

    Elf32_Half        e_shentsize;             /* Section header table entry size*/

    Elf32_Half        e_shnum;                 /* Section header table entrycount */

    Elf32_Half        e_shstrndx;              /* Section header string tableindex */

} Elf32_Ehdr;

 

64位:

typedef struct

{

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

    Elf64_Half        e_type;                  /*Object file type */

    Elf64_Half        e_machine;               /*Architecture */

    Elf64_Word        e_version;               /* Object file version */

    Elf64_Addr        e_entry;                 /* Entry point virtual address */

    Elf64_Off         e_phoff;                 /* Programheader table file offset */

    Elf64_Off         e_shoff;                 /* Sectionheader table file offset */

    Elf64_Word        e_flags;                 /*Processor-specific flags */

    Elf64_Half        e_ehsize;                /* ELF header sizein bytes */

    Elf64_Half        e_phentsize;             /* Program header table entry size */

    Elf64_Half        e_phnum;                 /* Program header table entry count */

    Elf64_Half        e_shentsize;             /* Section header table entry size */

    Elf64_Half        e_shnum;                 /* Section header table entry count */

    Elf64_Half        e_shstrndx;              /* Section header string table index */

} Elf64_Ehdr;

 

    因为我的ubuntulinux是64位的操作系统,所以下面的程序中,我用的是Elf64_Ehdr类型的结构体elfheader来存储文件头。其中,Elf64_Half是unsigned short int类型(2字节),Elf64_Word是unsigned int类型(4字节),Elf64_Addr是unsigned long int类型(8字节),Elf64_Off是unsigned long int类型(8字节)。程序以只读方式(r或者rb模式)打开目标文件elftest2.o,然后用fread函数从文件中读出一块大小为sizeof(Elf64_Ehdr)(64字节)的内容到elfheader中,最后把文件头中每一部分打印输出。

 

//read_ELFheader.c (ubuntu)

 

#include “stdio.h”

#include “/usr/include/elf.h”

int main()

{

         FILE * fp;

         int i;

         Elf64_Ehdr elfheader;

         fp= fopen(“elftest2.o”,”r”);

         fread(&elfheader,sizeof(Elf64_Ehdr),1,fp);

         for(i=0;i<16; i++)

                  printf(“%x”,elfheader.e_ident[i]);

         printf(“\n”);

         printf(“%hx\n”, elfheader.e_type);

         printf(“%hx\n”, elfheader.e_machine);

         printf(“%x\n”,  elfheader.e_version);

         printf(“%lx\n”, elfheader.e_entry);

         printf(“%lx\n”, elfheader.e_phoff);

         printf(“%lx\n”, elfheader.e_shoff);

         printf(“%x\n”,  elfheader.e_flags);

         printf(“%hx\n”, elfheader.e_ehsize);

         printf(“%hx\n”, elfheader.e_phentsize);

         printf(“%hx\n”, elfheader.e_phnum);

         printf(“%hx\n”, elfheader.e_shentsize);

         printf(“%hx\n”, elfheader.e_shnum);

         printf(“%hx\n”, elfheader.e_shstrndx);

         return 0;

} 

    

    读取了文件头以后,就可以利用elfheader.e_shoff (段表的偏移)来进一步读取段表,从而对各个段进行解析。

    原文作者:bufanq
    原文地址: https://blog.csdn.net/bufanq/article/details/51530875
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞