2013-04-13 37 views
6

Tôi phải viết chương trình C để in tệp ELF. Tôi đang gặp khó khăn trong việc tìm ra nơi mà bảng chuỗi phần tiêu đề là.Làm thế nào để tìm bù đắp của bảng chuỗi tiêu đề phần của tệp elf?

Hãy nói rằng tôi có một tập tin đó đã cho tôi đầu ra sau đây:

readelf -h

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:        REL (Relocatable file) 
    Machine:       Intel 80386 
    Version:       0x1 
    Entry point address:    0x0 
    Start of program headers:   0 (bytes into file) 
    Start of section headers:   17636 (bytes into file) 
    Flags:        0x0 
    Size of this header:    52 (bytes) 
    Size of program headers:   0 (bytes) 
    Number of program headers:   0 
    Size of section headers:   40 (bytes) 
    Number of section headers:   23 
    Section header string table index: 20 

và với:

readelf -S:

There are 23 section headers, starting at offset 0x44e4: 
Section Headers: 
    [Nr] Name    Type   Addr  Off Size ES Flg Lk Inf Al 
    [ 0]     NULL   00000000 000000 000000 00  0 0 0 
    [ 1] .text    PROGBITS  00000000 000034 000028 00 AX 0 0 4 
    [ 2] .rel.text   REL    00000000 0049d0 000018 08  21 1 4 
    [ 3] .data    PROGBITS  00000000 00005c 000000 00 WA 0 0 4 
    [ 4] .bss    NOBITS   00000000 00005c 000000 00 WA 0 0 4 
    [ 5] .rodata   PROGBITS  00000000 00005c 00000a 00 A 0 0 1 
    [ 6] .debug_info  PROGBITS  00000000 000066 00008f 00  0 0 1 
    [ 7] .rel.debug_info REL    00000000 0049e8 0000b0 08  21 6 4 
    [ 8] .debug_abbrev  PROGBITS  00000000 0000f5 000041 00  0 0 1 
    [ 9] .debug_loc  PROGBITS  00000000 000136 000038 00  0 0 1 
    [10] .debug_aranges PROGBITS  00000000 00016e 000020 00  0 0 1 
    [11] .rel.debug_arange REL    00000000 004a98 000010 08  21 10 4 
    [12] .debug_line  PROGBITS  00000000 00018e 0001b3 00  0 0 1 
    [13] .rel.debug_line REL    00000000 004aa8 000008 08  21 12 4 
    [14] .debug_macinfo PROGBITS  00000000 000341 003fb9 00  0 0 1 
    [15] .debug_str  PROGBITS  00000000 0042fa 0000bf 01 MS 0 0 1 
    [16] .comment   PROGBITS  00000000 0043b9 00002b 01 MS 0 0 1 
    [17] .note.GNU-stack PROGBITS  00000000 0043e4 000000 00  0 0 1 
    [18] .eh_frame   PROGBITS  00000000 0043e4 000038 00 A 0 0 4 
    [19] .rel.eh_frame  REL    00000000 004ab0 000008 08  21 18 4 
    [20] .shstrtab   STRTAB   00000000 00441c 0000c5 00  0 0 1 
    [21] .symtab   SYMTAB   00000000 00487c 000130 10  22 16 4 
    [22] .strtab   STRTAB   00000000 0049ac 000021 00  0 0 1 
Key to Flags: 
    W (write), A (alloc), X (execute), M (merge), S (strings) 
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) 
    O (extra OS processing required) o (OS specific), p (processor specific) 

Làm thế nào tôi có thể tính toán vị trí của bảng chuỗi tiêu đề phần?

+1

Nếu bạn tìm thấy nó trong 'ghex', bạn không thể thấy bù đắp bằng cách xem địa chỉ trong tệp mà bạn tìm thấy nó? Tôi không quen với nó, nhưng khi tôi googled nó một ảnh chụp màn hình đề nghị địa chỉ của xem vào tập tin là trong cột bên tay trái. – Floris

Trả lời

2

Có vẻ như trang bạn muốn là STRTAB, có độ lệch là 0x441c (dòng [20]). Các tiêu đề bắt đầu 17.636 byte vào tập tin (theo

Start of section headers:   17636 (bytes into file) 

Vì vậy, tôi sẽ đoán rằng bảng chuỗi của bạn bắt đầu tại 17.636 + 17.436 = 35.072 byte từ khi bắt đầu của tập tin.

tôi có thể . hoàn toàn sai, nhưng đó là nơi tôi sẽ bắt đầu bạn có biết làm thế nào để sử dụng od hoặc một số tiện ích như vậy để làm một bãi chứa tập tin byte

+0

Không, bù trừ là tuyệt đối. – zch

+0

Sau đó bảng chuỗi sẽ ở mức 17436 byte vào tệp? Nó sẽ được dễ dàng để kiểm tra xem một trong những điều này là chính xác. – Floris

13

Đây là những gì tôi làm:

#pragma pack(push,1) 

typedef struct 
{ 
    uint8 e_ident[16]; 
    uint16 e_type; 
    uint16 e_machine; 
    uint32 e_version; 
    uint32 e_entry; 
    uint32 e_phoff; 
    uint32 e_shoff; 
    uint32 e_flags; 
    uint16 e_ehsize; 
    uint16 e_phentsize; 
    uint16 e_phnum; 
    uint16 e_shentsize; 
    uint16 e_shnum; 
    uint16 e_shstrndx; 
} Elf32Hdr; 

typedef struct 
{ 
    uint32 sh_name; 
    uint32 sh_type; 
    uint32 sh_flags; 
    uint32 sh_addr; 
    uint32 sh_offset; 
    uint32 sh_size; 
    uint32 sh_link; 
    uint32 sh_info; 
    uint32 sh_addralign; 
    uint32 sh_entsize; 
} Elf32SectHdr; 

#pragma pack(pop) 

{ 
    FILE* ElfFile = NULL; 
    char* SectNames = NULL; 
    Elf32Hdr elfHdr; 
    Elf32SectHdr sectHdr; 
    uint idx; 

    // ... 

    // read ELF header 
    fread(&elfHdr, 1, sizeof elfHdr, ElfFile); 

    // read section name string table 
    // first, read its header 
    fseek(ElfFile, elfHdr.e_shoff + elfHdr.e_shstrndx * sizeof sectHdr, SEEK_SET); 
    fread(&sectHdr, 1, sizeof sectHdr, ElfFile); 

    // next, read the section, string data 
    SectNames = malloc(sectHdr.sh_size); 
    fseek(ElfFile, sectHdr.sh_offset, SEEK_SET); 
    fread(SectNames, 1, sectHdr.sh_size, ElfFile); 

    // read all section headers 
    for (idx = 0; idx < elfHdr.e_shnum; idx++) 
    { 
    const char* name = ""; 

    fseek(ElfFile, elfHdr.e_shoff + idx * sizeof sectHdr, SEEK_SET); 
    fread(&sectHdr, 1, sizeof sectHdr, ElfFile); 

    // print section name 
    if (sectHdr.sh_name); 
     name = SectNames + sectHdr.sh_name; 
    printf("%2u %s\n", idx, name); 
    } 

    // ... 
} 
4

Sau đây là cách bạn sẽ nhận được tên phần bảng chuỗi:

  • Các e_shstrndx lĩnh vực của ELF thực thi Header (EHDR) quy định các chỉ số của các mục nhập bảng phần tiêu đề mô tả tên phần bảng chuỗi chứa.
  • Trường e_shentsize của EHDR chỉ định kích thước tính bằng byte của mỗi mục trong bảng tiêu đề mục.
  • Trường e_shoff của EHDR chỉ định bù đắp tệp cho phần bắt đầu của bảng tiêu đề phần.

Như vậy mục tiêu đề cho bảng chuỗi sẽ có mặt tại file offset:

header_table_entry_offset = (e_shentsize * e_shstrndx) + e_shoff 

Tùy thuộc vào lớp ELF của đối tượng, mục tiêu đề bảng này sẽ là hoặc là một Elf32_Shdr hoặc một Elf64_Shdr. Lưu ý rằng biểu diễn tệp của mục nhập bảng tiêu đề có thể khác với biểu diễn trong bộ nhớ của nó trên máy chủ lưu trữ mà chương trình của bạn đang chạy.

Trường sh_offset trong mục nhập tiêu đề sẽ chỉ định độ lệch tệp bắt đầu của bảng chuỗi, trong khi trường sh_size sẽ chỉ định kích thước của nó.

Đọc thêm: Hướng dẫn "libelf by Example" bao gồm Tiêu đề ELF có thể thực thi và Bảng tiêu đề mục ELF ở độ sâu lớn hơn.