Example #1
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;
}
Example #2
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());
            }
        }
    }
}