Пример #1
0
/** Return true if the file looks like it might be a PE file according to the magic number.  The file must contain what
 *  appears to be a DOS File Header at address zero, and what appears to be a PE File Header at a file offset specified in
 *  part of the DOS File Header (actually, in the bytes that follow the DOS File Header). */
bool
SgAsmPEFileHeader::is_PE(SgAsmGenericFile *file)
{
    /* Turn off byte reference tracking for the duration of this function. We don't want our testing the file contents to
     * affect the list of bytes that we've already referenced or which we might reference later. */
    bool was_tracking = file->get_tracking_references();
    file->set_tracking_references(false);

    try {
        /* Check DOS File Header magic number at beginning of the file */
        unsigned char dos_magic[2];
        file->read_content(0, dos_magic, sizeof dos_magic);
        if ('M'!=dos_magic[0] || 'Z'!=dos_magic[1])
            throw 1;

        /* Read four-byte offset of potential PE File Header at offset 0x3c */
        uint32_t lfanew_disk;
        file->read_content(0x3c, &lfanew_disk, sizeof lfanew_disk);
        rose_addr_t pe_offset = le_to_host(lfanew_disk);
        
        /* Look for the PE File Header magic number */
        unsigned char pe_magic[4];
        file->read_content(pe_offset, pe_magic, sizeof pe_magic);
        if ('P'!=pe_magic[0] || 'E'!=pe_magic[1] || '\0'!=pe_magic[2] || '\0'!=pe_magic[3])
            throw 1;
    } catch (...) {
        file->set_tracking_references(was_tracking);
        return false;
    }
    
    file->set_tracking_references(was_tracking);
    return true;
}
Пример #2
0
// comment from Stefan Schneider-Kennedy:
// > 8 byte little endian. 2^(64) - number of 100ns intervals since timing
// > started. Like Microsoft's FILETIME. Round to nearest second.
static
float convert_time(const char* p)
{
    uint64_t d;
    memcpy(&d, p, sizeof(d));
    le_to_host(&d, sizeof(d));
    return (~d) * 1.0e-7f;
}
Пример #3
0
// comment from Stefan Schneider-Kennedy:
// > 8 byte little endian. Number of 100ns intervals since 1859.
// > Like Microsoft's FILETIME with an offset.
//
// comment from Stephan Messlinger:
// > The magic offset of 3506716800 seconds between the CNF time format to
// > unixtime does not point to 1859 but to Nov 17, 1958, 00:00. This is the
// > starting point for the 'Modified Julian Date', which is commonly used in
// > astronomy. Together with resolution of 100 ns, this points out to the DEC
// > VMS time format (which again fits to the PDP11 floating point format for
// > the energy coefficients).
//
static
string convert_date(const char* p)
{
    uint64_t d;
    memcpy(&d, p, sizeof(d));
    le_to_host(&d, sizeof(d));
    time_t t = d / 10000000 - 3506716800u; // time since the Epoch
    char s[64];
    int r = strftime(s, sizeof(s), "%a, %Y-%m-%d %H:%M:%S", gmtime(&t));
    if (r == 0)
        throw FormatError("reading date failed.");
    return string(s);
}
Пример #4
0
/** Initialize the header with information parsed from the file and construct and parse everything that's reachable from the
 *  header. The PE File Header should have been constructed such that SgAsmPEFileHeader::ctor() was called. */
SgAsmPEFileHeader*
SgAsmPEFileHeader::parse()
{
    SgAsmGenericHeader::parse();
    
    /* Read header, zero padding if the file isn't large enough */
    PEFileHeader_disk fh;
    if (sizeof(fh)>get_size())
        extend(sizeof(fh)-get_size());
    if (sizeof(fh)!=read_content_local(0, &fh, sizeof fh, false))
        fprintf(stderr, "SgAsmPEFileHeader::parse: warning: short read of PE header at byte 0x%08"PRIx64"\n", get_offset());

    /* Check magic number before getting too far */
    if (fh.e_magic[0]!='P' || fh.e_magic[1]!='E' || fh.e_magic[2]!='\0' || fh.e_magic[3]!='\0')
        throw FormatError("Bad PE magic number");

    /* Decode COFF file header */
    p_e_cpu_type           = le_to_host(fh.e_cpu_type);
    p_e_nsections          = le_to_host(fh.e_nsections);
    p_e_time               = le_to_host(fh.e_time);
    p_e_coff_symtab        = le_to_host(fh.e_coff_symtab);
    p_e_coff_nsyms         = le_to_host(fh.e_coff_nsyms);
    p_e_nt_hdr_size        = le_to_host(fh.e_nt_hdr_size);
    p_e_flags              = le_to_host(fh.e_flags);

    /* Read the "Optional Header" (optional in the sense that not all files have one, but required for an executable), the
     * size of which is stored in the e_nt_hdr_size of the main PE file header. According to 
     * http://www.phreedom.org/solar/code/tinype the Windows loader honors the e_nt_hdr_size even when set to smaller than the
     * smallest possible documented size of the optional header. Also it's possible for the optional header to extend beyond
     * the end of the file, in which case that part should be read as zero. */
    PE32OptHeader_disk oh32;
    rose_addr_t need32 = sizeof(PEFileHeader_disk) + std::min(p_e_nt_hdr_size, (rose_addr_t)(sizeof oh32));
    if (need32>get_size())
        extend(need32-get_size());
    if (sizeof(oh32)!=read_content_local(sizeof fh, &oh32, sizeof oh32, false))
        fprintf(stderr, "SgAsmPEFileHeader::parse: warning: short read of PE Optional Header at byte 0x%08"PRIx64"\n", 
                get_offset() + sizeof(fh));
    p_e_opt_magic = le_to_host(oh32.e_opt_magic);
    
    /* File format changes from ctor() */
    p_exec_format->set_purpose(p_e_flags & HF_PROGRAM ? PURPOSE_EXECUTABLE : PURPOSE_LIBRARY);
    p_exec_format->set_word_size(0x010b==p_e_opt_magic? 4 : 8);

    /* Decode the optional header. */
    rose_addr_t entry_rva;
    if (4==p_exec_format->get_word_size()) {
        p_e_lmajor             = le_to_host(oh32.e_lmajor);
        p_e_lminor             = le_to_host(oh32.e_lminor);
        p_e_code_size          = le_to_host(oh32.e_code_size);
        p_e_data_size          = le_to_host(oh32.e_data_size);
        p_e_bss_size           = le_to_host(oh32.e_bss_size);
        entry_rva              = le_to_host(oh32.e_entrypoint_rva);
        p_e_code_rva           = le_to_host(oh32.e_code_rva);
        p_e_data_rva           = le_to_host(oh32.e_data_rva);
        p_base_va              = le_to_host(oh32.e_image_base);
        p_e_section_align      = le_to_host(oh32.e_section_align);
        p_e_file_align         = le_to_host(oh32.e_file_align);
        p_e_os_major           = le_to_host(oh32.e_os_major);
        p_e_os_minor           = le_to_host(oh32.e_os_minor);
        p_e_user_major         = le_to_host(oh32.e_user_major);
        p_e_user_minor         = le_to_host(oh32.e_user_minor);
        p_e_subsys_major       = le_to_host(oh32.e_subsys_major);
        p_e_subsys_minor       = le_to_host(oh32.e_subsys_minor);
        p_e_reserved9          = le_to_host(oh32.e_reserved9);
        p_e_image_size         = le_to_host(oh32.e_image_size);
        p_e_header_size        = le_to_host(oh32.e_header_size);
        p_e_file_checksum      = le_to_host(oh32.e_file_checksum);
        p_e_subsystem          = le_to_host(oh32.e_subsystem);
        p_e_dll_flags          = le_to_host(oh32.e_dll_flags);
        p_e_stack_reserve_size = le_to_host(oh32.e_stack_reserve_size);
        p_e_stack_commit_size  = le_to_host(oh32.e_stack_commit_size);
        p_e_heap_reserve_size  = le_to_host(oh32.e_heap_reserve_size);
        p_e_heap_commit_size   = le_to_host(oh32.e_heap_commit_size);
        p_e_loader_flags       = le_to_host(oh32.e_loader_flags);
        p_e_num_rvasize_pairs  = le_to_host(oh32.e_num_rvasize_pairs);
    } else if (8==p_exec_format->get_word_size()) {
        /* We guessed wrong. This is a 64-bit header, not 32-bit. */
        PE64OptHeader_disk oh64;
        rose_addr_t need64 = sizeof(PEFileHeader_disk) + std::min(p_e_nt_hdr_size, (rose_addr_t)(sizeof oh64));
        if (need64>get_size())
            extend(need64-get_size());
        if (sizeof(oh64)!=read_content_local(sizeof fh, &oh64, sizeof oh64))
            fprintf(stderr, "SgAsmPEFileHeader::parse: warning: short read of PE Optional Header at byte 0x%08"PRIx64"\n", 
                    get_offset() + sizeof(fh));
        p_e_lmajor             = le_to_host(oh64.e_lmajor);
        p_e_lminor             = le_to_host(oh64.e_lminor);
        p_e_code_size          = le_to_host(oh64.e_code_size);
        p_e_data_size          = le_to_host(oh64.e_data_size);
        p_e_bss_size           = le_to_host(oh64.e_bss_size);
        entry_rva              = le_to_host(oh64.e_entrypoint_rva);
        p_e_code_rva           = le_to_host(oh64.e_code_rva);
     // p_e_data_rva           = le_to_host(oh.e_data_rva);             /* not in PE32+ */
        p_base_va              = le_to_host(oh64.e_image_base);
        p_e_section_align      = le_to_host(oh64.e_section_align);
        p_e_file_align         = le_to_host(oh64.e_file_align);
        p_e_os_major           = le_to_host(oh64.e_os_major);
        p_e_os_minor           = le_to_host(oh64.e_os_minor);
        p_e_user_major         = le_to_host(oh64.e_user_major);
        p_e_user_minor         = le_to_host(oh64.e_user_minor);
        p_e_subsys_major       = le_to_host(oh64.e_subsys_major);
        p_e_subsys_minor       = le_to_host(oh64.e_subsys_minor);
        p_e_reserved9          = le_to_host(oh64.e_reserved9);
        p_e_image_size         = le_to_host(oh64.e_image_size);
        p_e_header_size        = le_to_host(oh64.e_header_size);
        p_e_file_checksum      = le_to_host(oh64.e_file_checksum);
        p_e_subsystem          = le_to_host(oh64.e_subsystem);
        p_e_dll_flags          = le_to_host(oh64.e_dll_flags);
        p_e_stack_reserve_size = le_to_host(oh64.e_stack_reserve_size);
        p_e_stack_commit_size  = le_to_host(oh64.e_stack_commit_size);
        p_e_heap_reserve_size  = le_to_host(oh64.e_heap_reserve_size);
        p_e_heap_commit_size   = le_to_host(oh64.e_heap_commit_size);
        p_e_loader_flags       = le_to_host(oh64.e_loader_flags);
        p_e_num_rvasize_pairs  = le_to_host(oh64.e_num_rvasize_pairs);
    } else {
        throw FormatError("unrecognized Windows PE optional header magic number");
    }

    /* Magic number */
    p_magic.clear();
    for (size_t i = 0; i < sizeof(fh.e_magic); ++i)
        p_magic.push_back(fh.e_magic[i]);

    /* File format */
    ROSE_ASSERT(p_e_lmajor <= 0xffff && p_e_lminor <= 0xffff);
    p_exec_format->set_version((p_e_lmajor << 16) | p_e_lminor);
    p_exec_format->set_is_current_version(true); /*FIXME*/

    /* Target architecture */
    switch (p_e_cpu_type) {
      case 0x0000:
        set_isa(ISA_UNSPECIFIED);
        break;
      case 0x014c:
        set_isa(ISA_IA32_386);
        break;
      case 0x014d:
        set_isa(ISA_IA32_486);
        break;
      case 0x014e:
        set_isa(ISA_IA32_Pentium);
        break;
      case 0x0162:
        set_isa(ISA_MIPS_MarkI); /* R2000, R3000 */
        break;
      case 0x0163:
        set_isa(ISA_MIPS_MarkII); /* R6000 */
        break;
      case 0x0166:
        set_isa(ISA_MIPS_MarkIII); /* R4000 */
        break;
      case 0x01a2: /*Hitachi SH3*/
      case 0x01a3: /*Hitachi SH3 with FPU*/
      case 0x01a6: /*Hitachi SH4*/
      case 0x01a8: /*Hitachi SH5*/
        set_isa(ISA_Hitachi_SH);
        break;
      case 0x01c0:
        set_isa(ISA_ARM_Family);
        break;
      case 0x01d3:
        set_isa(ISA_Matsushita_AM33);
        break;
      case 0x01f0: /*w/o FPU*/
      case 0x01f1: /*with FPU*/
        set_isa(ISA_PowerPC);
        break;
      case 0x0200:
        set_isa(ISA_IA64_Family);
        break;
      case 0x0266:
        set_isa(ISA_MIPS_16);
        break;
      case 0x0366:
        set_isa(ISA_MIPS_FPU);
        break;
      case 0x0466:
        set_isa(ISA_MIPS_16FPU);
        break;
      case 0x0ebc:
        set_isa(ISA_EFI_ByteCode);
        break;
      case 0x8664:
        set_isa(ISA_X8664_Family);
        break;
      case 0x9041:
        set_isa(ISA_Mitsubishi_M32R);
        break;
      default:
        fprintf(stderr, "SgAsmPEFileHeader::parse: warning: unrecognized e_cputype = 0x%x (%u)\n", p_e_cpu_type, p_e_cpu_type);
        set_isa(ISA_OTHER);
        break;
    }

    /* The NT loader normally maps this file header at the header's base virtual address. */
    set_mapped_preferred_rva(0);
    set_mapped_actual_va(0); /* will be assigned by BinaryLoader */
    set_mapped_size(p_e_header_size);
    set_mapped_alignment(0);
    set_mapped_rperm(true);
    set_mapped_wperm(false);
    set_mapped_xperm(false);

    /* Entry point. We will eventually bind the entry point to a particular section (in SgAsmPEFileHeader::parse) so that if
     * sections are rearranged, extended, etc. the entry point will be updated automatically. */
    add_entry_rva(entry_rva);

    /* The PE File Header has a fixed-size component followed by some number of RVA/Size pairs. The add_rvasize_pairs() will
     * extend  the header and parse the RVA/Size pairs. */
    if (get_e_num_rvasize_pairs() > 1000) {
        fprintf(stderr, "warning: PE File Header contains an unreasonable number of Rva/Size pairs. Limiting to 1000.\n");
        set_e_num_rvasize_pairs(1000);
    }
    add_rvasize_pairs();

    /* Construct the section table and its sections (non-synthesized sections). The specification says that the section table
     * comes after the optional (NT) header, which in turn comes after the fixed part of the PE header. The size of the
     * optional header is indicated in the fixed header. */
    rose_addr_t secttab_offset = get_offset() + sizeof(PEFileHeader_disk) + get_e_nt_hdr_size();
    rose_addr_t secttab_size = get_e_nsections() * sizeof(SgAsmPESectionTableEntry::PESectionTableEntry_disk);
    SgAsmPESectionTable *secttab = new SgAsmPESectionTable(this);
    secttab->set_offset(secttab_offset);
    secttab->set_size(secttab_size);
    secttab->parse();
    set_section_table(secttab);

    /* Parse the COFF symbol table */
    if (get_e_coff_symtab() && get_e_coff_nsyms()) {
        SgAsmCoffSymbolTable *symtab = new SgAsmCoffSymbolTable(this);
        symtab->set_offset(get_e_coff_symtab());
        symtab->parse();
        set_coff_symtab(symtab);
    }

    /* Associate RVAs with particular sections so that if a section's mapping is changed the RVA gets adjusted automatically. */
    ROSE_ASSERT(get_entry_rvas().size()==1);
    get_entry_rvas()[0].bind(this);
    set_e_code_rva(get_e_code_rva().bind(this));
    set_e_data_rva(get_e_data_rva().bind(this));

    /* Turn header-specified tables (RVA/Size pairs) into generic sections */
    create_table_sections();
    return this;
}