/** Define an RVA/Size pair in the PE file header. */ void SgAsmPEFileHeader::set_rvasize_pair(PairPurpose idx, SgAsmPESection *section) { ROSE_ASSERT(get_rvasize_pairs()!=NULL); ROSE_ASSERT(section->get_parent()!=NULL); ROSE_ASSERT(isSgAsmPEFileHeader(section->get_header())!=NULL); if (idx>=16) fprintf(stderr, "SgAsmPEFileHeader::set_rvasize_pair: warning: index %u exceeds specification limit\n", (unsigned)idx); /* Extend array of rva/size pairs if necessary */ if ((size_t)idx>=get_rvasize_pairs()->get_pairs().size()) { get_rvasize_pairs()->get_pairs().resize(idx+1, NULL); for (size_t i=0; i<=(size_t)idx; i++) { if (NULL==get_rvasize_pairs()->get_pairs()[i]) { SgAsmPERVASizePair *pair = new SgAsmPERVASizePair(get_rvasize_pairs(), 0, 0); get_rvasize_pairs()->get_pairs()[i] = pair; } } } SgAsmPERVASizePair *pair = get_rvasize_pairs()->get_pairs()[idx]; ROSE_ASSERT(pair!=NULL); pair->set_e_rva(rose_rva_t(section->get_mapped_preferred_rva(), section)); pair->set_e_size(section->get_mapped_size()); pair->set_section(section); /* If the section has no name then give it one based on the RVA/Size index. This is mostly for convenience and debugging * since the name is never stored in the file. */ if (section->get_name()->get_string().empty()) { const char *short_name; section->get_name()->set_string(rvasize_pair_name(idx, &short_name)); section->set_short_name(short_name); } }
/** Class method to construct a new RVA which is an offset from the beginning of a section. The returned RVA is bound to the * supplied section. */ rose_rva_t rose_rva_t::section_relative(SgAsmGenericSection *section, rose_addr_t offset) { assert(section!=NULL); assert(section->is_mapped()); rose_addr_t rva =section->get_mapped_preferred_rva() + offset; return rose_rva_t(rva, section); }
/** Update all the RVA/Size pair info from the section to which it points. */ void SgAsmPEFileHeader::update_rvasize_pairs() { for (size_t i=0; i<get_rvasize_pairs()->get_pairs().size(); i++) { SgAsmPERVASizePair *pair = get_rvasize_pairs()->get_pairs()[i]; SgAsmGenericSection *section = pair->get_section(); if (section) { pair->set_e_rva(rose_rva_t(section->get_mapped_preferred_rva(), section)); pair->set_e_size(section->get_mapped_size()); } } }
void SgAsmPERVASizePair::set_section(SgAsmGenericSection *section) { if (section!=p_section) set_isModified(true); p_section = section; if (section) { set_e_rva(rose_rva_t(section->get_mapped_preferred_rva(), section)); set_e_size(section->get_mapped_size()); } else { set_e_rva(0); set_e_size(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::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at VA 0x%08"PRIx64 ": table entry is outside mapped memory\n", idx, entry_va) && e.map) { fprintf(stderr, " Memory map in effect at time of error:\n"); e.map->dump(stderr, " "); } } 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()) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirectory: IAT entry #%zu at va 0x%08"PRIx64 ": IAT zero termination occurs before end of corresponding ILT;" " %scontinuing to read IAT entries.\n", idx, entry_va, (assume_bound?"":"assuming this is a bound null address and ")); 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()) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirectory: IAT entry #%zu at va 0x%08"PRIx64 ": IAT extends beyond end of corresponding ILT (it is not zero terminated)" "; forcibly terminating here\n", idx, entry_va); 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) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": bound address 0x%08"PRIx64" conflicts with bound address already" " discovered 0x%08"PRIx64" (using new value)\n", idx, entry_va, entry_word, import_item->get_bound_rva().get_rva()); } 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)) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": ordinal %"PRIu64" conflicts with ordinal already discovered %u" " (assuming this is a bound address)\n", idx, entry_va, (entry_word&0xffff), import_item->get_ordinal()); 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))) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": contains extra bits in violation of PE specification" " (extra bits removed)\n", idx, entry_va); } } } 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()) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": entry type \"hint/name\" conflicts with entry type already discovered" " \"ordinal\" (assuming this is a bound address)\n", idx, entry_va); 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) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": hint/name rva 0x%08"PRIx64" conflicts with hint/name rva already" " discovered 0x%08"PRIx64" (assuming this is a bound address)\n", idx, entry_va, entry_word, import_item->get_hintname_rva().get_rva()); 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::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": points to unmapped Hint/Name pair at va 0x%08"PRIx64 " (when reading hint)\n", idx, entry_va, entry_word_va) && e.map) { fprintf(stderr, " Memory map in effect at time of error:\n"); e.map->dump(stderr, " "); } 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::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": points to an unmapped Hint/Name pair at va 0x%08"PRIx64 " (when reading name)\n", idx, entry_va, entry_word_va) && e.map) { fprintf(stderr, " Memory map in effect at time of error:\n"); e.map->dump(stderr, " "); } 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::import_mesg("SgAsmPEImportDirectory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": points to an unmapped Hint/Name pair at va 0x%08"PRIx64 " (when reading pad byte)\n", idx, entry_va, entry_word_va) && e.map) { fprintf(stderr, " Memory map in effect at time of error:\n"); e.map->dump(stderr, " "); } continue; // to next ILT/IAT entry } if (byte) { SgAsmPEImportSection::import_mesg("SgAsmPEImportDirctory: ILT/IAT entry #%zu at va 0x%08"PRIx64 ": has a non-zero padding byte: 0x%02x\n", idx, entry_va, byte); } } import_item->set_hintname_nalloc(import_item->hintname_required_size()); } } } }