2015-03-14 3 views
6

की सामग्री पढ़ना मैं एक ईएलएफ बाइनरी के भीतर एक अतिरिक्त खंड की सामग्री को पुनर्प्राप्त करने का प्रयास कर रहा हूं। इस बिंदु पर, मैं प्रत्येक अनुभाग के नाम को पुनः प्राप्त करने के लिए निम्न कोड का उपयोग कर रहा:ईएलएफ अनुभाग (प्रोग्रामेटिक रूप से)

#include <stdio.h> 
#include <unistd.h> 
#include <stdint.h> 
#include <stdlib.h> 

#pragma pack(push,1) 
#pragma pack(pop) 

#define EI_NIDENT  16 

/* 32-bit ELF base types. */ 
typedef unsigned int Elf32_Addr; 
typedef unsigned short Elf32_Half; 
typedef unsigned int Elf32_Off; 
typedef signed int Elf32_Sword; 
typedef unsigned int Elf32_Word; 

/* 64-bit ELF base types. */ 
typedef unsigned long long Elf64_Addr; 
typedef unsigned short Elf64_Half; 
typedef signed short Elf64_SHalf; 
typedef unsigned long long Elf64_Off; 
typedef signed int Elf64_Sword; 
typedef unsigned int Elf64_Word; 
typedef unsigned long long Elf64_Xword; 
typedef signed long long Elf64_Sxword; 

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_shdr { 
    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; 

typedef struct elf64_hdr { 
    unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ 
    Elf64_Half e_type; 
    Elf64_Half e_machine; 
    Elf64_Word e_version; 
    Elf64_Addr e_entry;  /* Entry point virtual address */ 
    Elf64_Off e_phoff;  /* Program header table file offset */ 
    Elf64_Off e_shoff;  /* Section header table file offset */ 
    Elf64_Word e_flags; 
    Elf64_Half e_ehsize; 
    Elf64_Half e_phentsize; 
    Elf64_Half e_phnum; 
    Elf64_Half e_shentsize; 
    Elf64_Half e_shnum; 
    Elf64_Half e_shstrndx; 
} Elf64_Ehdr; 

typedef struct elf64_shdr { 
    Elf64_Word sh_name;  /* Section name, index in string tbl */ 
    Elf64_Word sh_type;  /* Type of section */ 
    Elf64_Xword sh_flags;  /* Miscellaneous section attributes */ 
    Elf64_Addr sh_addr;  /* Section virtual addr at execution */ 
    Elf64_Off sh_offset;  /* Section file offset */ 
    Elf64_Xword sh_size;  /* Size of section in bytes */ 
    Elf64_Word sh_link;  /* Index of another section */ 
    Elf64_Word sh_info;  /* Additional section information */ 
    Elf64_Xword sh_addralign; /* Section alignment */ 
    Elf64_Xword sh_entsize; /* Entry size if section holds table */ 
} Elf64_Shdr; 



int main(int argc, char **argv) 
{ 
    FILE* ElfFile = NULL; 
    char* SectNames = NULL; 
    Elf64_Ehdr elfHdr; 
    Elf64_Shdr sectHdr; 
    uint32_t idx; 

    if(argc != 2) { 
    printf("usage: %s <ELF_FILE>\n", argv[0]); 
    exit(1); 
    } 

    if((ElfFile = fopen(argv[1], "r")) == NULL) { 
    perror("[E] Error opening file:"); 
    exit(1); 
    } 

    // read ELF header, first thing in the file 
    fread(&elfHdr, 1, sizeof(Elf64_Ehdr), ElfFile); 

    // read section name string table 
    // first, read its header. 
    /* 
    e_shoff   This member holds the section header table's file offset 
        in bytes. If the file has no section header table, this 
        member holds zero. 

    e_shstrndx  This member holds the section header table index of the 
       entry associated with the section name string table. If 
      the file has no section name string table, this member 
      holds the value SHN_UNDEF. 

      If the index of section name string table section is 
      larger than or equal to SHN_LORESERVE (0xff00), this 
      member holds SHN_XINDEX (0xffff) and the real index of 
      the section name string table section is held in the 
      sh_link member of the initial entry in section header 
      table. Otherwise, the sh_link member of the initial 
      entry in section header table contains the value zero. 

      SHN_UNDEF  This value marks an undefined, missing, 
         irrelevant, or otherwise meaningless 
         section reference. For example, a symbol 
         "defined" relative to section number 
         SHN_UNDEF is an undefined symbol. 

      SHN_LORESERVE This value specifies the lower bound of the 
         range of reserved indices. 

      SHN_LOPROC Values greater than or equal to SHN_HIPROC 
         are reserved for processor-specific 
         semantics. 

      SHN_HIPROC Values less than or equal to SHN_LOPROC are 
         reserved for processor-specific semantics. 

      SHN_ABS  This value specifies absolute values for 
         the corresponding reference. For example, 
         symbols defined relative to section number 
         SHN_ABS have absolute values and are not 
         affected by relocation. 

      SHN_COMMON Symbols defined relative to this section 
         are common symbols, such as Fortran COMMON 
         or unallocated C external variables. 

      SHN_HIRESERVE This value specifies the upper bound of the 
         range of reserved indices between 
         SHN_LORESERVE and SHN_HIRESERVE, inclusive; 
         the values do not reference the section 
         header table. That is, the section header 
         table does not contain entries for the 
         reserved indices. 
    */ 
    fseek(ElfFile, elfHdr.e_shoff + elfHdr.e_shstrndx * sizeof(sectHdr), SEEK_SET); 
    fread(&sectHdr, 1, sizeof(sectHdr), ElfFile); 
    /* 
    sh_size  This member holds the section's size in bytes. Unless the 
       section type is SHT_NOBITS, the section occupies sh_size 
       bytes in the file. A section of type SHT_NOBITS may have a 
       nonzero size, but it occupies no space in the file. 

    sh_offset  This member's value holds the byte offset from the 
       beginning of the file to the first byte in the section. 
       One section type, SHT_NOBITS, occupies no space in the 
       file, and its sh_offset member locates the conceptual 
       placement in the file. 

    e_shnum  This member holds the number of entries in the section 
       header table. Thus the product of e_shentsize and 
       e_shnum gives the section header table's size in bytes. 
       If a file has no section header table, e_shnum holds the 
       value of zero. 

       If the number of entries in the section header table is 
       larger than or equal to SHN_LORESERVE (0xff00), e_shnum 
       holds the value zero and the real number of entries in 
       the section header table is held in the sh_size member of 
       the initial entry in section header table. Otherwise, 
       the sh_size member of the initial entry in the section 
       header table holds the value zero. 

    sh_name  This member specifies the name of the section. Its value 
       is an index into the section header string table section, 
       giving the location of a null-terminated string. 
    */ 
    // next, read the section, string data 
    // printf("sh_size = %llu\n", sectHdr.sh_size); 
    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); 
    } 

    return 0; 
} 

एक "हैलो दुनिया" पर readelf रनिंग द्विआधारी का उत्पादन निम्नलिखित उत्पादन:

$ readelf -S helloworld 
There are 30 section headers, starting at offset 0x1170: 

Section Headers: 
    [Nr] Name    Type    Address   Offset 
     Size    EntSize   Flags Link Info Align 
    [ 0]     NULL    0000000000000000 00000000 
     0000000000000000 0000000000000000   0  0  0 
    [ 1] .interp   PROGBITS   0000000000400238 00000238 
     000000000000001c 0000000000000000 A  0  0  1 
    [ 2] .note.ABI-tag  NOTE    0000000000400254 00000254 
     0000000000000020 0000000000000000 A  0  0  4 
    [ 3] .note.gnu.build-i NOTE    0000000000400274 00000274 
     0000000000000024 0000000000000000 A  0  0  4 
    [ 4] .gnu.hash   GNU_HASH   0000000000400298 00000298 
     000000000000001c 0000000000000000 A  5  0  8 
    [ 5] .dynsym   DYNSYM   00000000004002b8 000002b8 
     0000000000000060 0000000000000018 A  6  1  8 
    [ 6] .dynstr   STRTAB   0000000000400318 00000318 
     000000000000003d 0000000000000000 A  0  0  1 
    [ 7] .gnu.version  VERSYM   0000000000400356 00000356 
     0000000000000008 0000000000000002 A  5  0  2 
    [ 8] .gnu.version_r VERNEED   0000000000400360 00000360 
     0000000000000020 0000000000000000 A  6  1  8 
    [ 9] .rela.dyn   RELA    0000000000400380 00000380 
     0000000000000018 0000000000000018 A  5  0  8 
    [10] .rela.plt   RELA    0000000000400398 00000398 
     0000000000000048 0000000000000018 A  5 12  8 
    [11] .init    PROGBITS   00000000004003e0 000003e0 
     000000000000001a 0000000000000000 AX  0  0  4 
    [12] .plt    PROGBITS   0000000000400400 00000400 
     0000000000000040 0000000000000010 AX  0  0  16 
    [13] .text    PROGBITS   0000000000400440 00000440 
     0000000000000182 0000000000000000 AX  0  0  16 
    [14] .fini    PROGBITS   00000000004005c4 000005c4 
     0000000000000009 0000000000000000 AX  0  0  4 
    [15] .rodata   PROGBITS   00000000004005d0 000005d0 
     0000000000000013 0000000000000000 A  0  0  4 
    [16] .eh_frame_hdr  PROGBITS   00000000004005e4 000005e4 
     0000000000000034 0000000000000000 A  0  0  4 
    [17] .eh_frame   PROGBITS   0000000000400618 00000618 
     00000000000000f4 0000000000000000 A  0  0  8 
    [18] .init_array  INIT_ARRAY  0000000000600e10 00000e10 
     0000000000000008 0000000000000000 WA  0  0  8 
    [19] .fini_array  FINI_ARRAY  0000000000600e18 00000e18 
     0000000000000008 0000000000000000 WA  0  0  8 
    [20] .jcr    PROGBITS   0000000000600e20 00000e20 
     0000000000000008 0000000000000000 WA  0  0  8 
    [21] .dynamic   DYNAMIC   0000000000600e28 00000e28 
     00000000000001d0 0000000000000010 WA  6  0  8 
    [22] .got    PROGBITS   0000000000600ff8 00000ff8 
     0000000000000008 0000000000000008 WA  0  0  8 
    [23] .got.plt   PROGBITS   0000000000601000 00001000 
     0000000000000030 0000000000000008 WA  0  0  8 
    [24] .data    PROGBITS   0000000000601030 00001030 
     0000000000000010 0000000000000000 WA  0  0  8 
    [25] .bss    NOBITS   0000000000601040 00001040 
     0000000000000008 0000000000000000 WA  0  0  1 
    [26] .comment   PROGBITS   0000000000000000 00001040 
     0000000000000024 0000000000000001 MS  0  0  1 
    [27] .shstrtab   STRTAB   0000000000000000 00001064 
     0000000000000108 0000000000000000   0  0  1 
    [28] .symtab   SYMTAB   0000000000000000 000018f0 
     0000000000000618 0000000000000018   29 45  8 
    [29] .strtab   STRTAB   0000000000000000 00001f08 
     000000000000023c 0000000000000000   0  0  1 
Key to Flags: 
    W (write), A (alloc), X (execute), M (merge), S (strings), l (large) 
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) 
    O (extra OS processing required) o (OS specific), p (processor specific) 

की जांच निम्नलिखित प्रविष्टि:

[13] .text    PROGBITS   0000000000400440 00000440 
      0000000000000182 0000000000000000 AX  0  0  16 
आदेश .text अनुभाग entirel को पुनः प्राप्त करने में

बाइनरी से y फ़ाइल से 0x400440 + 0x440 पते से 0x182 बाइट पढ़ने के लिए पर्याप्त है? जहां 0x182 अनुभाग का आकार है और 0x400440 पता है और 0x440 ऑफ़सेट है? इसके अलावा, संरेखण (0x16) की भूमिका क्या है?

उत्तर

9

.text अनुभाग निकालने के लिए आपको 0x182 (Size) बाइट्स को अपनी बाइनरी फ़ाइल में 0x440 (Offset) पते से शुरू करने की आवश्यकता है।

पर ध्यान न दें 0x400440 (Address) मूल्य है, यह फ़ाइल पते के साथ कोई संबंध नहीं है, यह रैम स्मृति में पता जहाँ आपके .text अनुभाग loader से कॉपी किया जाएगा है। ELF format specification से:

sh_addr: खंड एक प्रक्रिया की स्मृति छवि में दिखाई देगा, तो यह सदस्य पता जिस पर खंड की पहली बाइट होनी चाहिए देता है। अन्यथा, सदस्य 0.

Align मान वास्तव में दशमलव है, हेक्साडेसिमल नहीं है। तो यह 16 है, 0x16 नहीं। संरेखण का अर्थ है कि सेक्शन पता 16 (बाइट्स) के एकाधिक होना चाहिए।


आप अपने आप से बाइनरी की खोज करके यह सब सत्यापित कर सकते हैं। सबसे पहले, अपने द्विआधारी का जुदा निरीक्षण:

$ objdump -D your-file | less 

ढूँढें जहां .text शुरू होता है और फिर .text अनुभाग डेटा को देखें।

$ hexdump -C your-file | less 

अब Offset पते खोजने के लिए और इस पते से शुरू बाइट्स को देखो: अब सिर्फ एक गूंगा hexdump आपरेशन करते हैं। आप पाएंगे कि वे .text खंड से अलग वही बाइट्स हैं।

निष्कर्ष: आप जब आपकी फ़ाइल, नहीं Address मूल्य के साथ काम (readelf उत्पादन से) Offset मान का उपयोग करने की जरूरत है।

संबंधित मुद्दे