天天看點

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

繼續閱讀