Beispiel #1
0
/* Pre-unparsing updates */
bool
SgAsmPESectionTable::reallocate()
{
    bool reallocated = false;
    
    /* Resize based on section having largest ID */
    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr != NULL);
    SgAsmGenericSectionPtrList sections = fhdr->get_sections()->get_sections();
    int max_id = 0;
    for (size_t i=0; i<sections.size(); i++) {

        max_id = std::max(max_id, sections[i]->get_id());

        }
    
    size_t nsections = max_id; /*PE section IDs are 1-origin*/
    size_t need = nsections * sizeof(SgAsmPESectionTableEntry::PESectionTableEntry_disk);
    if (need < get_size()) {
        if (is_mapped()) {
            ROSE_ASSERT(get_mapped_size()==get_size());
            set_mapped_size(need);
        }
        set_size(need);
        reallocated = true;
    } else if (need > get_size()) {
        get_file()->shift_extend(this, 0, need-get_size(), SgAsmGenericFile::ADDRSP_ALL, SgAsmGenericFile::ELASTIC_HOLE);
        reallocated = true;
    }

    return reallocated;
}
Beispiel #2
0
/** Number of bytes required for the table.  Returns the number of bytes required for the entire IAT or ILT (including the zero
 *  terminator) as it is currently defined in the Import Directory.  The returned size does not include space required to store
 *  any Hint/Name pairs, which are outside the ILT/IAT but pointed to by the ILT/IAT. */
size_t
SgAsmPEImportDirectory::iat_required_size() const
{
    SgAsmPEFileHeader *fhdr = SageInterface::getEnclosingNode<SgAsmPEFileHeader>(this);
    assert(fhdr!=NULL);
    return (p_imports->get_vector().size() + 1) * fhdr->get_word_size();
}
Beispiel #3
0
/** Attaches a previously unattached PE Section to the PE Section Table. This method complements
 *  SgAsmPESection::init_from_section_table. This method initializes the section table from the section while
 *  init_from_section_table() initializes the section from the section table. */
void
SgAsmPESectionTable::add_section(SgAsmPESection *section)
{
    ROSE_ASSERT(section!=NULL);
    ROSE_ASSERT(section->get_file()==get_file());
    ROSE_ASSERT(section->get_header()==get_header());
    ROSE_ASSERT(section->get_section_entry()==NULL);            /* must not be in the section table yet */
    
    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);
    
    /* Assign an ID if there isn't one yet. */
    if (section->get_id()<0) {
        SgAsmGenericSectionList *seclist = fhdr->get_sections();;
        int max_id=0; /*assume zero is used so we start at one*/
        for (size_t i=0; i<seclist->get_sections().size(); i++) {
            SgAsmGenericSection *s = seclist->get_sections()[i];

                        max_id = std::max(max_id, s->get_id());

                }
        section->set_id(max_id+1);
    }
    
    /* Create a new section table entry. */
    SgAsmPESectionTableEntry *entry = new SgAsmPESectionTableEntry;
    entry->update_from_section(section);
    section->set_section_entry(entry);
}
Beispiel #4
0
/* Constructor */
void
SgAsmPEExportDirectory::ctor(SgAsmPEExportSection *section)
{
    SgAsmPEFileHeader *fhdr = isSgAsmPEFileHeader(section->get_header());
    ROSE_ASSERT(fhdr!=NULL);
    set_parent(section);

    /* Read disk-formatted export directory */
    PEExportDirectory_disk disk;
    try {
        section->read_content(fhdr->get_loader_map(), section->get_mapped_actual_va(), &disk, sizeof disk);
    } catch (const MemoryMap::NotMapped &e) {
        if (mlog[ERROR]) {
            mlog[ERROR] <<"SgAsmPEExportDirectory::ctor: export directory at va "
                        <<StringUtility::addrToString(section->get_mapped_actual_va())
                        <<" contains unmapped va " <<StringUtility::addrToString(e.va) <<"\n";
            if (e.map) {
                mlog[ERROR] <<"Memory map in effect at time of error:\n";
                e.map->dump(mlog[ERROR], "    ");
            }
        }
        memset(&disk, 0, sizeof disk);
    }
    
    /* Convert disk-format data members to native format */
    p_res1         = ByteOrder::le_to_host(disk.res1);
    p_timestamp    = ByteOrder::le_to_host(disk.timestamp);
    p_vmajor       = ByteOrder::le_to_host(disk.vmajor);
    p_vminor       = ByteOrder::le_to_host(disk.vminor);
    p_name_rva     = ByteOrder::le_to_host(disk.name_rva);       p_name_rva.set_section(section);
    p_ord_base     = ByteOrder::le_to_host(disk.ord_base);
    p_expaddr_n    = ByteOrder::le_to_host(disk.expaddr_n);
    p_nameptr_n    = ByteOrder::le_to_host(disk.nameptr_n);
    p_expaddr_rva  = ByteOrder::le_to_host(disk.expaddr_rva);    p_expaddr_rva.set_section(section);
    p_nameptr_rva  = ByteOrder::le_to_host(disk.nameptr_rva);    p_nameptr_rva.set_section(section);
    p_ordinals_rva = ByteOrder::le_to_host(disk.ordinals_rva);   p_ordinals_rva.set_section(section);

    /* Read the name */
    std::string name;
    try {
        name = section->read_content_str(fhdr->get_loader_map(), p_name_rva.get_va());
    } catch (const MemoryMap::NotMapped &e) {
        if (mlog[WARN]) {
            mlog[WARN] <<"SgAsmPEExportDirectory::ctor: directory name at rva "
                       <<StringUtility::addrToString(p_name_rva.get_rva())
                       <<" contains unmapped va " <<StringUtility::addrToString(e.va) <<"\n";
            if (e.map) {
                mlog[WARN] <<"Memory map in effect at time of error:\n";
                e.map->dump(mlog[WARN], "    ");
            }
        }
        memset(&disk, 0, sizeof disk);
    }
    p_name = new SgAsmBasicString(name);
    p_name->set_parent(this);
}
Beispiel #5
0
/* Constructor */
void
SgAsmPESectionTable::ctor()
{
    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);
    fhdr->set_section_table(this);

    set_synthesized(true);
    set_name(new SgAsmBasicString("PE Section Table"));
    set_purpose(SP_HEADER);
}
Beispiel #6
0
/* Parser */
SgAsmPESectionTable*
SgAsmPESectionTable::parse()
{
    SgAsmGenericSection::parse();

    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);

    /* Parse section table and construct section objects, but do not parse the sections yet. */
    SgAsmGenericSectionPtrList pending;
    const size_t entsize = sizeof(SgAsmPESectionTableEntry::PESectionTableEntry_disk);
    for (size_t i=0; i<fhdr->get_e_nsections(); i++) {
        SgAsmPESectionTableEntry::PESectionTableEntry_disk disk;
        if (entsize!=read_content_local(i * entsize, &disk, entsize, false))
            fprintf(stderr, "SgAsmPESectionTable::parse: warning: section table entry %" PRIuPTR " at file offset 0x%08"PRIx64
                    " extends beyond end of defined section table.\n",
                    i, get_offset()+i*entsize);
        SgAsmPESectionTableEntry *entry = new SgAsmPESectionTableEntry(&disk);

        SgAsmPESection *section = NULL;
        if (entry->get_name() == ".idata") {
            section = new SgAsmPEImportSection(fhdr);
        } else {
            section = new SgAsmPESection(fhdr);
        }
        section->init_from_section_table(entry, i+1);
        pending.push_back(section);
    }

    /* Build the memory mapping like the real loader would do. This is the same code used by
     * SgAsmExecutableFileFormat::parseBinaryFormat() except we're doing it here early because we need it in the rest of the
     * PE parser. */
    ROSE_ASSERT(NULL==fhdr->get_loader_map());
    BinaryLoader *loader = BinaryLoader::lookup(fhdr); /*no need to clone; we're not changing any settings*/
    ROSE_ASSERT(loader!=NULL);
    MemoryMap *loader_map = new MemoryMap;
    loader->remap(loader_map, fhdr);
    fhdr->set_loader_map(loader_map);

    /* Parse each section after the loader map is created */
    for (size_t i=0; i<pending.size(); i++)
        pending[i]->parse();

    return this;
}
Beispiel #7
0
/* Writes the section table back to disk. */
void
SgAsmPESectionTable::unparse(std::ostream &f) const
{
    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr != NULL);
    SgAsmGenericSectionPtrList sections = fhdr->get_sections()->get_sections();

    for (size_t i = 0; i < sections.size(); i++) {
        if (sections[i]->get_id()>=0) {
            SgAsmPESection *section = isSgAsmPESection(sections[i]);
            ROSE_ASSERT(section!=NULL);

            /* Write the table entry */
            ROSE_ASSERT(section->get_id() > 0); /*ID's are 1-origin in PE*/
            size_t slot = section->get_id() - 1;
            SgAsmPESectionTableEntry *shdr = section->get_section_entry();
            SgAsmPESectionTableEntry::PESectionTableEntry_disk disk;
            shdr->encode(&disk);
            write(f, slot*sizeof(disk), sizeof disk, &disk);
        }
    }
}
SgAsmCoffSymbolTable*
SgAsmCoffSymbolTable::parse()
{
    /* Set the section size according to the number of entries indicated in the header. */
    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);
    set_offset(fhdr->get_e_coff_symtab());
    set_size(fhdr->get_e_coff_nsyms()*SgAsmCoffSymbol::COFFSymbol_disk_size);

    SgAsmGenericSection::parse();

    /* The string table immediately follows the symbols. The first four bytes of the string table are the size of the
     * string table in little endian. */
    rose_addr_t strtab_offset = get_offset() + fhdr->get_e_coff_nsyms() * SgAsmCoffSymbol::COFFSymbol_disk_size;
    p_strtab = new SgAsmGenericSection(fhdr->get_file(), fhdr);
    p_strtab->set_offset(strtab_offset);
    p_strtab->set_size(sizeof(uint32_t));
    p_strtab->set_synthesized(true);
    p_strtab->set_name(new SgAsmBasicString("COFF Symbol Strtab"));
    p_strtab->set_purpose(SP_HEADER);
    p_strtab->parse();

    uint32_t word;
    p_strtab->read_content(0, &word, sizeof word);
    rose_addr_t strtab_size = ByteOrder::le_to_host(word);
    if (strtab_size < sizeof(uint32_t))
        throw FormatError("COFF symbol table string table size is less than four bytes");
    p_strtab->extend(strtab_size - sizeof(uint32_t));

    /* Parse symbols until we've parsed the required number or we run off the end of the section. */
    for (size_t i = 0; i < fhdr->get_e_coff_nsyms(); i++) {
        try {
            SgAsmCoffSymbol *symbol = new SgAsmCoffSymbol(fhdr, this, p_strtab, i);
            i += symbol->get_st_num_aux_entries();
            p_symbols->get_symbols().push_back(symbol);
        } catch (const ShortRead &e) {
            fprintf(stderr, "SgAsmCoffSymbolTable::parse: warning: read past end of section \"%s\" [%d]\n"
                    "    symbol #%zu at file offset 0x%08"PRIx64"\n"
                    "    skipping %zu symbols (including this one)\n",
                    get_name()->get_string(true).c_str(), get_id(),
                    i, e.offset,
                    fhdr->get_e_coff_nsyms()-i);
            break;
        }
    }

    return this;
}
Beispiel #9
0
SgAsmPEExportSection*
SgAsmPEExportSection::parse()
{
    SgAsmPESection::parse();

    SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
    ROSE_ASSERT(fhdr!=NULL);

    p_export_dir = new SgAsmPEExportDirectory(this);

    /* The export directory points to three parallel arrays:
     *   1. An array of RVAs that point to NUL-terminated names.
     *   2. An array of "ordinals" which serve as indices into the Export Address Table.
     *   3. An array of export addresses (see note below). */
    for (size_t i=0; i<p_export_dir->get_nameptr_n(); i++) {
        /* Function name RVA (nameptr)*/
        ExportNamePtr_disk nameptr_disk = 0;
        rose_addr_t nameptr_va = p_export_dir->get_nameptr_rva().get_va() + i*sizeof(nameptr_disk);
        bool badFunctionNameVa = false;
        try {
            read_content(fhdr->get_loader_map(), nameptr_va, &nameptr_disk, sizeof nameptr_disk);
        } catch (const MemoryMap::NotMapped &e) {
            badFunctionNameVa = true;
            if (mlog[ERROR]) {
                mlog[ERROR] <<"SgAsmPEExportSection::parse: export name #" <<i
                            <<" at va " <<StringUtility::addrToString(nameptr_va)
                            <<" contains unmapped va " <<StringUtility::addrToString(e.va) <<"\n";
                if (e.map) {
                    mlog[ERROR] <<"Memory map in effect at time of error:\n";
                    e.map->dump(mlog[ERROR], "    ");
                }
            }
            nameptr_disk = 0;
        }
        rose_addr_t fname_rva = ByteOrder::le_to_host(nameptr_disk);
        rose_addr_t fname_va = fname_rva + fhdr->get_base_va();

        /* Function name (fname) */
        std::string s;
        try {
            s = read_content_str(fhdr->get_loader_map(), fname_va);
        } catch (const MemoryMap::NotMapped &e) {
            if (mlog[ERROR]) {
                mlog[ERROR] <<"SgAsmPEExportSection::parse: export name #" <<i
                            <<" at va " <<StringUtility::addrToString(fname_va)
                            <<" contains unmapped va " <<StringUtility::addrToString(e.va) <<"\n";
                if (e.map) {
                    mlog[ERROR] <<"Memory map in effect at time of error:\n";
                    e.map->dump(mlog[ERROR], "    ");
                }
            }
        }
        SgAsmGenericString *fname = new SgAsmBasicString(s);

        /* Ordinal (sort of an index into the Export Address Table) */
        ExportOrdinal_disk ordinal_disk = 0;
        rose_addr_t ordinal_va = p_export_dir->get_ordinals_rva().get_va() + i*sizeof(ordinal_disk);
        bool badOrdinalVa = false;
        try {
            read_content(fhdr->get_loader_map(), ordinal_va, &ordinal_disk, sizeof ordinal_disk);
        } catch (const MemoryMap::NotMapped &e) {
            badOrdinalVa = true;
            if (mlog[ERROR]) {
                mlog[ERROR] <<"SgAsmPEExportSection::parse: ordinal #" <<i
                            <<" at va " <<StringUtility::addrToString(ordinal_va)
                            <<" contains unmapped va " <<StringUtility::addrToString(e.va) <<"\n";
                if (e.map) {
                    mlog[ERROR] <<"Memory map in effect at time of error:\n";
                    e.map->dump(mlog[ERROR], "    ");
                }
            }
            ordinal_disk = 0;
        }
        unsigned ordinal = ByteOrder::le_to_host(ordinal_disk);

        /* If the function name pointer and ordinal pointer are both in unmapped memory then give up. */
        if (badFunctionNameVa && badOrdinalVa) {
            if (mlog[ERROR])
                mlog[ERROR] <<"SgAsmPEExportSection::parse: giving up after trying to read entry #" <<i <<"\n";
            break;
        }

        /* Export address. Convert the symbol's Ordinal into an index into the Export Address Table. The spec says to subtract
         * the ord_base from the Ordinal to get the index, but testing has shown this to be off by one (e.g., Windows-XP file
         * /WINDOWS/system32/msacm32.dll's Export Table's first symbol has the name "XRegThunkEntry" with an Ordinal of zero
         * and the ord_base is one. The index according to spec would be -1 rather than the correct value of zero.) */
        rose_rva_t expaddr = 0;
        if (ordinal >= (p_export_dir->get_ord_base()-1)) {
            unsigned expaddr_idx = ordinal - (p_export_dir->get_ord_base()-1);
            ROSE_ASSERT(expaddr_idx < p_export_dir->get_expaddr_n());
            ExportAddress_disk expaddr_disk = 0;
            rose_addr_t expaddr_va = p_export_dir->get_expaddr_rva().get_va() + expaddr_idx*sizeof(expaddr_disk);
            try {
                read_content(fhdr->get_loader_map(), expaddr_va, &expaddr_disk, sizeof expaddr_disk);
            } catch (const MemoryMap::NotMapped &e) {
                if (mlog[ERROR]) {
                    mlog[ERROR] <<"SgAsmPEExportSection::parse: export address #" <<i
                                <<" at va " <<StringUtility::addrToString(expaddr_va)
                                <<" contains unmapped va " <<StringUtility::addrToString(e.va) <<"\n";
                    if (e.map) {
                        mlog[ERROR] <<"Memory map in effect at time of error:\n";
                        e.map->dump(mlog[ERROR], "    ");
                    }
                }
            }
            expaddr = ByteOrder::le_to_host(expaddr_disk);
            expaddr.bind(fhdr);
        } else {
            expaddr = 0xffffffff; /*Ordinal out of range!*/
        }

        /* If export address is within this section then it points to a NUL-terminated forwarder name.
         * FIXME: Is this the proper precondition? [RPM 2009-08-20] */
        SgAsmGenericString *forwarder = NULL;
        if (expaddr.get_va()>=get_mapped_actual_va() && expaddr.get_va()<get_mapped_actual_va()+get_mapped_size()) {
            std::string s;
            try {
                s = read_content_str(fhdr->get_loader_map(), expaddr.get_va());
            } catch (const MemoryMap::NotMapped &e) {
                if (mlog[ERROR]) {
                    mlog[ERROR] <<"SgAsmPEExportSection::parse: forwarder " <<i
                                <<" at rva " <<StringUtility::addrToString(expaddr.get_rva())
                                <<" contains unmapped va " <<StringUtility::addrToString(e.va) <<"\n";
                    if (e.map) {
                        mlog[ERROR] <<"Memory map in effect at time of error:\n";
                        e.map->dump(mlog[ERROR], "    ");
                    }
                }
            }
            forwarder = new SgAsmBasicString(s);
        }

        SgAsmPEExportEntry *entry = new SgAsmPEExportEntry(fname, ordinal, expaddr, forwarder);
        add_entry(entry);
    }
    return this;
}
Beispiel #10
0
/** Parse an import directory. The import directory is parsed from the specified virtual address via the PE header's loader
 *  map. Return value is this directory entry on success, or the null pointer if the entry is all zero (which marks the end of
 *  the directory list). */
SgAsmPEImportDirectory *
SgAsmPEImportDirectory::parse(rose_addr_t idir_va)
{
    SgAsmPEFileHeader *fhdr = SageInterface::getEnclosingNode<SgAsmPEFileHeader>(this);
    ROSE_ASSERT(fhdr!=NULL);

    /* Read the import directory from disk via loader map. */
    PEImportDirectory_disk disk, zero;
    memset(&zero, 0, sizeof zero);
    size_t nread = fhdr->get_loader_map()->readQuick(&disk, idir_va, sizeof disk);
    if (nread!=sizeof disk) {
        if (SgAsmPEImportSection::show_import_mesg()) {
            mlog[WARN] <<"SgAsmPEImportDirectory::parse: short read (" <<StringUtility::plural(nread, "bytes") <<")"
                       <<" of directory at va " <<StringUtility::addrToString(idir_va)
                       <<" (needed " <<StringUtility::plural(sizeof disk, "bytes") <<")\n";
        }
        memset(&disk, 0, sizeof disk);
    }

    /* An all-zero entry marks the end of the list. In this case return null. */
    if (!memcmp(&disk, &zero, sizeof zero))
        return NULL;

    p_ilt_rva         = ByteOrder::le_to_host(disk.ilt_rva);
    p_time            = ByteOrder::le_to_host(disk.time);
    p_forwarder_chain = ByteOrder::le_to_host(disk.forwarder_chain);
    p_dll_name_rva    = ByteOrder::le_to_host(disk.dll_name_rva);
    p_iat_rva         = ByteOrder::le_to_host(disk.iat_rva);

    /* Bind RVAs to best sections */
    p_ilt_rva.bind(fhdr);
    p_dll_name_rva.bind(fhdr);
    p_iat_rva.bind(fhdr);

    /* Library name.  The PE format specification does not require the name to be contained in the import section, but we issue
     * a warning because ROSE may have problems allocating new space for the name if it's changed. */
    ROSE_ASSERT(p_dll_name!=NULL);
    std::string dll_name;
    if (0==p_dll_name_rva.get_section()) {
        if (SgAsmPEImportSection::show_import_mesg()) {
            mlog[WARN] <<"SgAsmPEImportDirectory::parse: import directory at va " <<StringUtility::addrToString(idir_va)
                       <<" has bad DLL name rva " <<p_dll_name_rva <<"\n";
        }
    } else {
        try {
            dll_name = p_dll_name_rva.get_section()->read_content_str(fhdr->get_loader_map(), p_dll_name_rva.get_va());
        } catch (const MemoryMap::NotMapped &e) {
            if (SgAsmPEImportSection::show_import_mesg()) {
                mlog[WARN] <<"SgAsmPEImportDirectory::parse: short read of dll name at rva "
                           << p_dll_name_rva <<" for import directory at va " <<StringUtility::addrToString(idir_va) <<"\n";
                if (e.map) {
                    mlog[WARN] <<"    Memory map in effect at time of error is:\n";
                    e.map->dump(mlog[WARN], "        ");
                }
            }
        }
    }
    p_dll_name->set_string(dll_name);
    p_dll_name_nalloc = dll_name.size() + 1;

    parse_ilt_iat(p_ilt_rva, false);
    p_ilt_nalloc = 0==p_ilt_rva.get_rva() ? 0 : iat_required_size();

    parse_ilt_iat(p_iat_rva, false); // IAT initially is a copy of the ILT (i.e., objects are not bound to addresses yet)
    p_iat_nalloc = 0==p_iat_rva.get_rva() ? 0 : iat_required_size();

    return this;
}
Beispiel #11
0
/** Unparse a PE Import Lookup Table or Import Address Table.  The @p table_start address is the location where the ILT or IAT
 *  begins and should be bound to the section to which the table is being written.  The table is filled with ordinals and/or
 *  hint/name pairs unless @p assume_bound is set, in which case the table is filled with the bound addresses.  The PE spec
 *  requires that the IAT in the executable file has the exact same structure and content as the ILT, so this method is
 *  normally called wtih @p assume_bound set to false.
 *
 *  The @p tablesize argument is the number of bytes allocated for the table, and may be less than the number of bytes required
 *  to write the entire table.  This can happen, for instance, when the AST was modified by adding entries to the ILT/IAT but
 *  the size (and probably location) of the table could not be changed.  This is typical of IATs since code in the .text
 *  section often references IAT entries via indirect jumps/calls and it is infeasible to move the IAT to a new location.  If
 *  unparsing is unable to write all table entries due to the @p tablesize limit, an error message is printed. */
void
SgAsmPEImportDirectory::unparse_ilt_iat(std::ostream &f, const rose_rva_t &table_start, bool assume_bound,
                                        size_t tablesize) const
{
    SgAsmPEImportSection *isec = SageInterface::getEnclosingNode<SgAsmPEImportSection>(this);
    assert(isec!=NULL);
    SgAsmPEFileHeader *fhdr = isSgAsmPEFileHeader(isec->get_header());
    assert(fhdr!=NULL);
    assert(fhdr->get_word_size() <= sizeof(uint64_t));
    const SgAsmPEImportItemPtrList &imports = get_imports()->get_vector();
    size_t entry_size = fhdr->get_word_size();
    uint64_t by_ordinal_bit = 1ull << (8*entry_size-1);

    if (0==table_start.get_rva() || imports.empty())
        return;
    if (!table_start.get_section()) {
        if (SgAsmPEImportSection::show_import_mesg()) {
            mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT: table is not associated with a section: "
                       <<table_start.to_string() <<"\n";
        }
        return;
    }

    /* Must we limit how many entries are written? Don't forget the zero terminator. */
    size_t nelmts = std::min(tablesize/entry_size, imports.size()+1);
    if (nelmts<imports.size()+1) {
        if (SgAsmPEImportSection::show_import_mesg()) {
            mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT: table at " <<table_start.to_string()
                       <<" is truncated from " <<StringUtility::plural(imports.size()+1, "entries", "entry")
                       <<" to " <<StringUtility::plural(nelmts, "entries", "entry")
                       <<" (inc. zero terminator) due to allocation constraints.\n";
        }
    }

    rose_rva_t entry_rva = table_start;
    for (size_t idx=0; idx<nelmts/*including zero terminator*/; ++idx, entry_rva.increment(entry_size)) {
        uint64_t entry_word = 0;

        /* Write the zero terminator? */
        if (idx+1==nelmts) {
            uint64_t zero = 0;
            entry_rva.get_section()->write(f, entry_rva.get_rel(), entry_size, &zero);
            break;
        }

        rose_rva_t hn_rva = imports[idx]->get_hintname_rva();

        /* Build the IAT/ILT entry */
        if (assume_bound) {
            entry_word = imports[idx]->get_bound_rva().get_rva();
        } else if (imports[idx]->get_by_ordinal()) {
            if (0!=(imports[idx]->get_ordinal() & ~0xffff)) {
                if (SgAsmPEImportSection::show_import_mesg()) {
                    mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                               <<" at rva " <<entry_rva.get_rva()
                               <<": ordinal is out of bounds: " <<imports[idx]->get_ordinal() <<" (truncated to 16 bits)\n";
                }
            }
            entry_word |= by_ordinal_bit | (imports[idx]->get_ordinal() & 0xffff);
        } else if (0==hn_rva.get_rva() || NULL==hn_rva.get_section()) {
            if (SgAsmPEImportSection::show_import_mesg()) {
                mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                           <<" at rva " <<entry_rva.get_rva()
                           <<": non-ordinal entry has invalid hint/name pair address " <<hn_rva
                           <<" or is not associated with any section.\n";
            }
            entry_word = hn_rva.get_rva(); // best we can do
        } else {
            size_t bufsz = std::min(imports[idx]->get_hintname_nalloc(), imports[idx]->hintname_required_size());
            if (bufsz < imports[idx]->hintname_required_size()) {
                if (SgAsmPEImportSection::show_import_mesg()) {
                    mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                               <<" at rva " <<entry_rva.get_rva()
                               <<": insufficient space (" <<StringUtility::plural(bufsz, "bytes") <<")"
                               <<" allocated for hint/name pair at rva " <<hn_rva
                               <<" (need " <<StringUtility::plural(imports[idx]->hintname_required_size(), "bytes") <<")\n";
                }
            }
            if (bufsz>=2) {
                uint8_t *buf = new uint8_t[bufsz];
                unsigned hint = imports[idx]->get_hint();
                std::string name = imports[idx]->get_name()->get_string();
                if (0!=(hint & ~0xffff)) {
                    if (SgAsmPEImportSection::show_import_mesg()) {
                        mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                                   <<" at rva " <<entry_rva.get_rva()
                                   <<": hint is out of bounds: " <<hint <<" (truncated to 16 bits)\n";
                    }
                }
                ByteOrder::host_to_le(hint, &hint); // nudge, nudge. Know what I mean?
                memcpy(buf, &hint, 2);
                memcpy(buf+2, name.c_str(), std::min(name.size()+1, bufsz-2));
                if (bufsz>2)
                    buf[bufsz-1] = '\0';
                hn_rva.get_section()->write(f, hn_rva.get_rel(), bufsz, buf);
                if (0!=(hn_rva.get_rva() & by_ordinal_bit)) {
                    if (SgAsmPEImportSection::show_import_mesg()) {
                        mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                                   <<" at rva " <<entry_rva.get_rva()
                                   <<": hint/name pair rva " <<hn_rva.get_rva()
                                   <<" has by_ordinal bit set\n";
                    }
                }
                delete[] buf;
            }
            entry_word = hn_rva.get_rva() & ~by_ordinal_bit;
        }

        /* Write the IAT/ILT entry */
        if (0==entry_word) {
            if (SgAsmPEImportSection::show_import_mesg()) {
                mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                           <<" at rva " <<entry_rva.get_rva()
                           <<": zero table entry will cause table to be truncated when read\n";
            }
        }
        uint64_t disk = 0; // we might write only the first few bytes
        ByteOrder::host_to_le(entry_word, &disk);
        entry_rva.get_section()->write(f, entry_rva.get_rel(), entry_size, &disk);
    }
}
Beispiel #12
0
/** Parse an Import Lookup Table or Import Address Table.  The table begins at the specified address and consists of 32- or 64-
 *  bit vectors which are (1) an ordinal number with high order bit set, (2) a relative virtual address of a hint/name pair, or
 *  (3) a virtual address filled in by the dynamic linker when the shared object is bound.  The last case is assumed if @p
 *  @p assume_bound is set.
 *
 *  Normally, the ILT and IAT of an executable file have identical structure and content and the IAT is changed only after the
 *  shared objects are dynamically linked.  However, we might encounter cases where we discover that the IAT has values that
 *  are different than the ILT even when @p assume_bound is false.  When this happens, we emit a warning message and treat the
 *  conflicting IAT entry as a bound address. */
void
SgAsmPEImportDirectory::parse_ilt_iat(const rose_rva_t &table_start, bool assume_bound)
{
    SgAsmPEImportSection *isec = SageInterface::getEnclosingNode<SgAsmPEImportSection>(this);
    assert(isec!=NULL);
    SgAsmPEFileHeader *fhdr = isSgAsmPEFileHeader(isec->get_header());
    assert(fhdr!=NULL);
    assert(fhdr->get_word_size() <= sizeof(uint64_t));
    assert(get_imports()!=NULL);
    SgAsmPEImportItemPtrList &imports = get_imports()->get_vector();
    bool processing_iat = !imports.empty(); // we always process the ILT first (but it might be empty)

    if (0==table_start.get_rva())
        return;                 // no ILT/IAT present


    rose_addr_t entry_va=table_start.get_va(), entry_size=fhdr->get_word_size();
    uint64_t by_ordinal_bit = 1ull << (8*entry_size-1);

    for (size_t idx=0; 1; ++idx, entry_va+=entry_size) {
        /* Read the 32- or 64-bit ILT/IAT entry from proces mapped memory. */
        uint64_t entry_word = 0;
        try {
            isec->read_content(fhdr->get_loader_map(), entry_va, &entry_word, entry_size);
        } catch (const MemoryMap::NotMapped &e) {
            if (SgAsmPEImportSection::show_import_mesg()) {
                mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                           <<" at va " <<StringUtility::addrToString(entry_va)
                           <<": table entry is outside mapped memory\n";
                if (e.map) {
                    mlog[WARN] <<"    Memory map in effect at time of error:\n";
                    e.map->dump(mlog[WARN], "        ");
                }
            }
        }
        entry_word = ByteOrder::le_to_host(entry_word);

        /* ILT/IAT are to be terminated by a zero word.  However, the length of the IAT is required to be the same as the
         * length of the ILT. Handle three cases here:
         *      (1) Termination of the ILT by a zero entry; stop now
         *      (2) Premature termination of the IAT; continue processing
         *      (3) Missing (or late) termination of the IAT; stop now */
        if (0==entry_word) {
            if (idx<imports.size()) {
                if (SgAsmPEImportSection::show_import_mesg()) {
                    mlog[ERROR] <<"SgAsmPEImportDirectory: IAT entry #" <<idx
                                <<" at va " <<StringUtility::addrToString(entry_va)
                                <<": IAT zero termination occurs before end of corresponding ILT;"
                                <<(assume_bound?"":"assuming this is a bound null address and ")
                                <<" continuing to read IAT entries.\n";
                }
                assert(idx<imports.size());
                imports[idx]->set_bound_rva(rose_rva_t(entry_word).bind(fhdr));
                continue;
            } else {
                break;
            }
        } else if (processing_iat && idx>=imports.size()) {
            if (SgAsmPEImportSection::show_import_mesg()) {
                mlog[WARN] <<"SgAsmPEImportDirectory: IAT entry #" <<idx
                           <<" at va " <<StringUtility::addrToString(entry_va)
                           <<": IAT extends beyond end of corresponding ILT (it is not zero terminated)"
                           <<"; forcibly terminating here\n";
            }
            break;
        }

        /* Create the new table entry if necessary. */
        bool entry_existed = true;
        if (idx>=imports.size()) {
            assert(idx==imports.size());
            new SgAsmPEImportItem(get_imports()); // adds new item to imports list
            entry_existed = false;
        }
        SgAsmPEImportItem *import_item = imports[idx];

        if (assume_bound) {
            /* The entry word is a virtual address. */
            if (entry_existed && import_item->get_bound_rva().get_rva()>0 &&
                    import_item->get_bound_rva().get_rva()!=entry_word) {
                if (SgAsmPEImportSection::show_import_mesg()) {
                    mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                               <<" at va " <<StringUtility::addrToString(entry_va)
                               <<": bound address " <<StringUtility::addrToString(entry_word)
                               <<" conflicts with bound address already discovered "
                               <<import_item->get_bound_rva().get_rva() <<" (using new value)\n";
                }
            }
            import_item->set_bound_rva(rose_rva_t(entry_word).bind(fhdr));
        } else if (0!=(entry_word & by_ordinal_bit)) {
            /* The entry is an ordinal number. */
            if (entry_existed && import_item->get_ordinal()!=0 && import_item->get_ordinal()!=(entry_word & 0xffff)) {
                if (SgAsmPEImportSection::show_import_mesg()) {
                    mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                               <<" at va " <<StringUtility::addrToString(entry_va)
                               <<": ordinal " <<(entry_word & 0xffff) <<" conflicts with ordinal already discovered "
                               <<import_item->get_ordinal()
                               <<" (assuming this is a bound address)\n";
                }
                import_item->set_bound_rva(rose_rva_t(entry_word).bind(fhdr));
            } else {
                import_item->set_by_ordinal(true);
                import_item->set_ordinal(entry_word & 0xffff);
                if (0!=(entry_word & ~(by_ordinal_bit | 0xffff))) {
                    if (SgAsmPEImportSection::show_import_mesg()) {
                        mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                                   <<" at va " <<StringUtility::addrToString(entry_va)
                                   <<": contains extra bits in violation of PE specification"
                                   <<" (extra bits removed)\n";
                    }
                }
            }
        } else {
            /* The entry word points to a Hint/Name pair: a 2-byte, little endian hint, followed by a NUL-terminated string,
             * followed by an optional extra byte to make the total length a multiple of two. */
            if (entry_existed && import_item->get_by_ordinal()) {
                if (SgAsmPEImportSection::show_import_mesg()) {
                    mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                               <<" at va " <<StringUtility::addrToString(entry_va)
                               <<": entry type \"hint/name\" conflicts with entry type already discovered"
                               <<" \"ordinal\" (assuming this is a bound address)\n";
                }
                import_item->set_bound_rva(rose_rva_t(entry_word).bind(fhdr));
            } else if (entry_existed && import_item->get_hintname_rva().get_rva()>0 &&
                       import_item->get_hintname_rva().get_rva()!=entry_word) {
                if (SgAsmPEImportSection::show_import_mesg()) {
                    mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                               <<" at va " <<StringUtility::addrToString(entry_va)
                               <<": hint/name rva " <<entry_word
                               <<" conflicts with hint/name rva already discovered "
                               <<import_item->get_hintname_rva().get_rva()
                               <<" (assuming this is a bound address)\n";
                }
                import_item->set_bound_rva(rose_rva_t(entry_word).bind(fhdr));
            } else {
                import_item->set_by_ordinal(false);
                import_item->set_hintname_rva(rose_rva_t(entry_word).bind(fhdr));
                import_item->set_hintname_nalloc(0); // for now, will adjust after we read it
                rose_addr_t entry_word_va = entry_word + fhdr->get_base_va();
                uint16_t hint;
                try {
                    isec->read_content(fhdr->get_loader_map(), entry_word_va, &hint, sizeof hint);
                } catch (const MemoryMap::NotMapped &e) {
                    import_item->set_hint(0);
                    import_item->get_name()->set_string("");
                    if (SgAsmPEImportSection::show_import_mesg()) {
                        mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                                   <<" at va " <<StringUtility::addrToString(entry_va)
                                   <<": points to unmapped Hint/Name pair at va "
                                   <<StringUtility::addrToString(entry_word_va) <<"\n";
                        if (e.map) {
                            mlog[WARN] <<"    Memory map in effect at time of error:\n";
                            e.map->dump(mlog[WARN], "        ");
                        }
                    }
                    continue; // to next ILT/IAT entry
                }
                hint = ByteOrder::le_to_host(hint);
                import_item->set_hint(hint);

                std::string s;
                try {
                    s = isec->read_content_str(fhdr->get_loader_map(), entry_word_va+2);
                } catch (const MemoryMap::NotMapped &e) {
                    import_item->get_name()->set_string("");
                    if (SgAsmPEImportSection::show_import_mesg()) {
                        mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                                   <<" at va " <<StringUtility::addrToString(entry_va)
                                   <<": points to an unmapped Hint/Name pair at va "
                                   <<StringUtility::addrToString(entry_word_va) <<"\n";
                        if (e.map) {
                            mlog[WARN] <<"    Memory map in effect at time of error:\n";
                            e.map->dump(mlog[WARN], "        ");
                        }
                    }
                    continue; // to next ILT/IAT entry
                }
                import_item->get_name()->set_string(s);

                if ((s.size()+1)  % 2) {
                    uint8_t byte = 0;
                    try {
                        isec->read_content(fhdr->get_loader_map(), entry_word_va+2+s.size()+1, &byte, 1);
                    } catch (const MemoryMap::NotMapped &e) {
                        if (SgAsmPEImportSection::show_import_mesg()) {
                            mlog[WARN] <<"SgAsmPEImportDirectory: ILT/IAT entry #" <<idx
                                       <<" at va " <<StringUtility::addrToString(entry_va)
                                       <<": points to an unmapped Hint/Name pair at va "
                                       <<StringUtility::addrToString(entry_word_va)
                                       <<" (when reading pad byte)\n";
                            if (e.map) {
                                mlog[WARN] <<"    Memory map in effect at time of error:\n";
                                e.map->dump(mlog[WARN], "        ");
                            }
                        }
                        continue; // to next ILT/IAT entry
                    }
                    if (byte) {
                        if (SgAsmPEImportSection::show_import_mesg()) {
                            mlog[WARN] <<"SgAsmPEImportDirctory: ILT/IAT entry #" <<idx
                                       <<" at va " <<StringUtility::addrToString(entry_va)
                                       <<": has a non-zero padding byte: "
                                       <<StringUtility::toHex2(byte, 8) <<"\n";
                        }
                    }
                }
                import_item->set_hintname_nalloc(import_item->hintname_required_size());
            }
        }
    }
}
Beispiel #13
0
/** Update this section table entry with newer information from the section */
void
SgAsmPESectionTableEntry::update_from_section(SgAsmPESection *section)
{
    SgAsmPEFileHeader *fhdr = SageInterface::getEnclosingNode<SgAsmPEFileHeader>(section);
    ROSE_ASSERT(fhdr!=NULL);

    p_virtual_size = section->get_mapped_size();
    p_rva = section->get_mapped_preferred_rva();
    p_physical_size = section->get_size();
    p_physical_offset = section->get_offset();
    p_name = section->get_name()->get_string();

    /* Mapping permissions */
    if (section->get_mapped_rperm()) {
        p_flags |= SgAsmPESectionTableEntry::OF_READABLE;
    } else {
        p_flags &= ~SgAsmPESectionTableEntry::OF_READABLE;
    }
    if (section->get_mapped_wperm()) {
        p_flags |= SgAsmPESectionTableEntry::OF_WRITABLE;
    } else {
        p_flags &= ~SgAsmPESectionTableEntry::OF_WRITABLE;
    }
    if (section->get_mapped_xperm()) {
        p_flags |= SgAsmPESectionTableEntry::OF_EXECUTABLE;
    } else {
        p_flags &= ~SgAsmPESectionTableEntry::OF_EXECUTABLE;
    }

    /* Mapping alignment */
    if (section->is_mapped() && section->get_mapped_alignment()!=fhdr->get_e_section_align()) {
        switch (section->get_mapped_alignment()) {
            case 0:
            case 1:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_1;
                break;
            case 2:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_2;
                break;
            case 4:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_4;
                break;
            case 8:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_8;
                break;
            case 16:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_16;
                break;
            case 32:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_32;
                break;
            case 64:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_64;
                break;
            case 128:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_128;
                break;
            case 256:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_256;
                break;
            case 512:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_512;
                break;
            case 1024:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_1k;
                break;
            case 2048:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_2k;
                break;
            case 4096:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_4k;
                break;
            case 8192:
                p_flags &= ~SgAsmPESectionTableEntry::OF_ALIGN_MASK;
                p_flags |=  SgAsmPESectionTableEntry::OF_ALIGN_8k;
                break;
            default:
                break; /* leave as is */
        }
    }

#if 0 /*FIXME*/
    p_coff_line_nums = 0;
    p_n_relocs = 0;
    p_n_coff_line_nums = 0;
#endif
}