天天看点

ELF Section Header 分析

ELF Section Header的结构还是要从/usr/include/elf.h中看。

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;

同样,可以算出来Elf32_Shdr的大小是40B。其结构中的各个元素数据类型在elf.h中同样可以找到,含义见注释。整个section header table就是一个数组,数组的每一个元素就是Elf32_Shdr。Elf32_Shdr仅仅是section的一个索引,包括一些属性信息,并不是section本省。简单的介绍一下各个元素的含义。

sh_name: section name。不过其实sh_name中存放的是index,不是字符串,这一点从sh_name是定长应该能看出来,那么index又是什么意思呢?index的含义是在string tabl总的第几个字节数。其实是这样的,所有的section name都存放在一个叫做string table的表中,index就是该section名字的第一个字符在表中的位置,名字一直到遇到一个'\0'为止结束。至于string table怎么找,还记得上一篇中提到的elf header中的e_shstrndx成员吗,它就指明了string table是在section header table中的第几个入口。

sh_offset:这个元素就指明了这个Elf32_Shdr描述的section在文件中的偏移量。

其他各个变量可以查询《Executable and Linkable Format(ELF)》这个文档。

为了检验程序输出结果的对错,我们与readelf这个命令的输出结果作比较。

下面编程序来输出文件的section信息。首先要找到section header table在文件中的位置,回忆一下,section header table的偏移量在elf header中的e_shoff中告诉了我们,所以,我们就知道了section header table在文件中的位置了,同样,我们在elf header中可以找到section header的大小及个数,这样我们用一个循环就可以输出出来每个section的信息了。

    fseek(fp, elfheader.e_shoff, SEEK_SET);

    shnum = elfheader.e_shnum;

    printf("Number of Section headers: %d\n\n", shnum);

    while(shnum != 0){

        fread(&shdr, sizeof(char), sizeof(shdr), fp);

        printf("sh_name : %d\n", shdr.sh_name);

        printf("sh_type : %#x\n", shdr.sh_type);

        printf("sh_flags : %d\n", shdr.sh_flags);

        printf("sh_addr : %#x\n", shdr.sh_addr);

        printf("sh_offset : %d\n", shdr.sh_offset);

        printf("sh_size : %d\n", shdr.sh_size);

        printf("sh_link : %d\n", shdr.sh_link);

        printf("sh_info : %d\n", shdr.sh_info);

        printf("sh_addralign : %d\n", shdr.sh_addralign);

        printf("sh_entsize : %d\n\n", shdr.sh_entsize);

        shnum--;

    }

输出的结果如下:

Number of Section headers: 34

sh_name : 0

sh_type : 0

sh_flags : 0

sh_addr : 0

sh_offset : 0

sh_size : 0

sh_link : 0

sh_info : 0

sh_addralign : 0

sh_entsize : 0

sh_name : 27

sh_type : 0x1

sh_flags : 2

sh_addr : 0x80480f4

sh_offset : 244

sh_size : 19

sh_link : 0

sh_info : 0

sh_addralign : 1

sh_entsize : 0

sh_name : 35

sh_type : 0x7

sh_flags : 2

sh_addr : 0x8048108

sh_offset : 264

sh_size : 32

sh_link : 0

sh_info : 0

sh_addralign : 4

sh_entsize : 0

...

观察上面的结果可以看到,sh_name并不是section的名字,而是一个数字。回忆前面提到的,sh_name存放的只是section name在string table的index。因此,为了输出section name我们必须先得到string table。string table的信息也在section header table中存放,只要我们得到了string table header的内容,就可以从里面的sh_offset知道string table的位置,从sh_size知道string table的大小。此时问题就成为如何找到string talbe header在section header table中的位置,即index.回忆前面讲到的,elf header中有一个变量e_shstrndx存放的就是string table header在section header中的index。此时整个思路已经明白了,即elfheader.e_shstrndx --> string table header --> string table。string table里面到底是什么呢?其实就是一些带'\0'的字符串。比如\0.bss\0.text\0\0,那么如果sh_name是1,则该sh_name代表的是从string table中零开始的直到遇到\0为止的字符串,即.bss。整个程序如下:

    fseek(fp, elfheader.e_shoff + elfheader.e_shstrndx*elfheader.e_shentsize, SEEK_SET);

    fread(&strhdr, sizeof(char), sizeof(strhdr), fp);//get the string table header

    fseek(fp, strhdr.sh_offset, SEEK_SET);

    strtable = (unsigned char *)malloc(sizeof(unsigned char)*strhdr.sh_size);

    fread(strtable, sizeof(char), strhdr.sh_size, fp);

    fseek(fp, elfheader.e_shoff, SEEK_SET);

    shnum = elfheader.e_shnum;

    printf("Number of Section headers: %d\n\n", shnum);

    while(shnum != 0){

        fread(&shdr, sizeof(char), sizeof(shdr), fp);

        printf("sh_name : %s\n", strtable+shdr.sh_name);

        printf("sh_type : %#x\n", shdr.sh_type);

        printf("sh_flags : %d\n", shdr.sh_flags);

        printf("sh_addr : %#x\n", shdr.sh_addr);

        printf("sh_offset : %d\n", shdr.sh_offset);

        printf("sh_size : %d\n", shdr.sh_size);

        printf("sh_link : %d\n", shdr.sh_link);

        printf("sh_info : %d\n", shdr.sh_info);

        printf("sh_addralign : %d\n", shdr.sh_addralign);

        printf("sh_entsize : %d\n\n", shdr.sh_entsize);

        shnum--;

    }

程序的输出结果为:

Number of Section headers: 34

sh_name :

sh_type : 0

sh_flags : 0

sh_addr : 0

sh_offset : 0

sh_size : 0

sh_link : 0

sh_info : 0

sh_addralign : 0

sh_entsize : 0

sh_name : .interp

sh_type : 0x1

sh_flags : 2

sh_addr : 0x80480f4

sh_offset : 244

sh_size : 19

sh_link : 0

sh_info : 0

sh_addralign : 1

sh_entsize : 0

sh_name : .note.ABI-tag

sh_type : 0x7

sh_flags : 2

sh_addr : 0x8048108

sh_offset : 264

sh_size : 32

sh_link : 0

sh_info : 0

sh_addralign : 4

sh_entsize : 0

sh_name : .hash

sh_type : 0x5

sh_flags : 2

sh_addr : 0x8048128

sh_offset : 296

sh_size : 64

sh_link : 4

sh_info : 0

sh_addralign : 4

sh_entsize : 4

继续阅读