bool PE::_parse_hint_name_table(pimport_lookup_table import) const { int size_to_read = (get_architecture() == PE::x86 ? 4 : 8); // Read the HINT/NAME TABLE if applicable. Check the most significant byte of AddressOfData to // see if the import is by name or ordinal. For PE32+, AddressOfData is a uint64. boost::uint64_t mask = (size_to_read == 8 ? 0x8000000000000000 : 0x80000000); if (!(import->AddressOfData & mask)) { // Import by name. Read the HINT/NAME table. For both PE32 and PE32+, its RVA is stored // in bits 30-0 of AddressOfData. unsigned int table_offset = _rva_to_offset(import->AddressOfData & 0x7FFFFFFF); if (table_offset == 0) { PRINT_ERROR << "Could not reach the HINT/NAME table." << std::endl; return false; } long saved_offset = ftell(_file_handle.get()); if (saved_offset == -1 || fseek(_file_handle.get(), table_offset, SEEK_SET) || 2 != fread(&(import->Hint), 1, 2, _file_handle.get())) { PRINT_ERROR << "Could not read a HINT/NAME hint." << std::endl; return false; } import->Name = utils::read_ascii_string(_file_handle.get()); //TODO: Demangle the import name // Go back to the import lookup table. if (fseek(_file_handle.get(), saved_offset, SEEK_SET)) { return false; } } return true; }
bool PE::_parse_delayed_imports() { if (!_ioh || _file_handle == nullptr) { // Image Optional Header wasn't parsed successfully. return false; } if (!_reach_directory(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)) { // No delayed imports return true; } delay_load_directory_table dldt; memset(&dldt, 0, 8*sizeof(boost::uint32_t)); if (1 != fread(&dldt, 8*sizeof(boost::uint32_t), 1, _file_handle.get())) { PRINT_WARNING << "Could not read the Delay-Load Directory Table!" << std::endl; return true; } unsigned int offset = _rva_to_offset(dldt.Name); if (offset == 0) { PRINT_WARNING << "Could not read the name of the DLL to be delay-loaded!" << std::endl; return true; } // Read the delayed DLL's name std::string name; utils::read_string_at_offset(_file_handle.get(), offset, name); pImportedLibrary library(new ImportedLibrary(name)); dldt.NameStr = name; _delay_load_directory_table.reset(dldt); // Read the imports offset = _rva_to_offset(dldt.DelayImportNameTable); if (_parse_import_lookup_table(offset, library)) { _imports.push_back(library); } return true; }
bool PE::_parse_imports() { if (!_ioh || _file_handle == nullptr) { // Image Optional Header wasn't parsed successfully. return false; } if (!_reach_directory(IMAGE_DIRECTORY_ENTRY_IMPORT)) { // No imports return true; } while (true) // We stop at the first NULL IMAGE_IMPORT_DESCRIPTOR. { pimage_import_descriptor iid(new image_import_descriptor); memset(iid.get(), 0, 5*sizeof(boost::uint32_t)); // Don't overwrite the last member (a string) if (20 != fread(iid.get(), 1, 20, _file_handle.get())) { PRINT_ERROR << "Could not read the IMAGE_IMPORT_DESCRIPTOR." << std::endl; return true; // Don't give up on the rest of the parsing. } // Exit condition if (iid->OriginalFirstThunk == 0 && iid->FirstThunk == 0) { break; } // Non-standard parsing. The Name RVA is translated to an actual string here. auto offset = _rva_to_offset(iid->Name); if (!offset) { // Try to use the RVA as a direct address if the imports are outside of a section. offset = iid->Name; } std::string library_name; if (!utils::read_string_at_offset(_file_handle.get(), offset, library_name)) { // It seems that the Windows loader doesn't give up if such a thing happens. if (_imports.size() > 0) { PRINT_WARNING << "Could not read an import's name." << std::endl; break; // Try to continue the parsing with the available imports. } PRINT_ERROR << "Could not read an import's name." << std::endl; return true; } pImportedLibrary library = pImportedLibrary(new ImportedLibrary(library_name, iid)); _imports.push_back(library); } // Parse the IMPORT_LOOKUP_TABLE for each imported library for (auto it = _imports.begin() ; it != _imports.end() ; ++it) { int ilt_offset; auto descriptor = (*it)->get_image_import_descriptor(); if (descriptor == nullptr) { // Should never happen, standard (as opposed to delay-loaded) imports all have image import descriptors. PRINT_WARNING << "Tried to parse imported functions, but no image import descriptor was given!" << DEBUG_INFO_INSIDEPE << std::endl; continue; } if (descriptor->OriginalFirstThunk != 0) { ilt_offset = _rva_to_offset(descriptor->OriginalFirstThunk); } else { // Some packed executables use FirstThunk and set OriginalFirstThunk to 0. ilt_offset = _rva_to_offset(descriptor->FirstThunk); } if (!_parse_import_lookup_table(ilt_offset, *it)) { // Non fatal. Stop trying to parse imports, but the ones already read will still be available. if ((*it)->get_name() != nullptr) { PRINT_WARNING << "An error occurred while trying to read functions imported by " << *(*it)->get_name() << "." << DEBUG_INFO_INSIDEPE << std::endl; } return true; } } return true; }
bool PE::_parse_imports(FILE* f) { if (!_ioh) { // Image Optional Header wasn't parsed successfully. return false; } if (!_reach_directory(f, IMAGE_DIRECTORY_ENTRY_IMPORT)) { // No imports return true; } while (true) // We stop at the first NULL IMAGE_IMPORT_DESCRIPTOR. { pimage_import_descriptor iid(new image_import_descriptor); memset(iid.get(), 0, 5*sizeof(boost::uint32_t)); // Don't overwrite the last member (a string) if (20 != fread(iid.get(), 1, 20, f)) { PRINT_ERROR << "Could not read the IMAGE_IMPORT_DESCRIPTOR." << std::endl; return true; // Don't give up on the rest of the parsing. } // Exit condition if (iid->OriginalFirstThunk == 0 && iid->FirstThunk == 0) { break; } // Non-standard parsing. The Name RVA is translated to an actual string here. auto offset = _rva_to_offset(iid->Name); if (!offset) { // Try to use the RVA as a direct address if the imports are outside of a section. offset = iid->Name; } if (!utils::read_string_at_offset(f, offset, iid->NameStr)) { // It seems that the Windows loader doesn't give up if such a thing happens. if (_imports.size() > 0) { PRINT_WARNING << "Could not read an import's name." << std::endl; break; // Try to continue the parsing with the available imports. } PRINT_ERROR << "Could not read an import's name." << std::endl; return true; } pimage_library_descriptor library = boost::make_shared<image_library_descriptor>(iid, std::vector<pimport_lookup_table>()); _imports.push_back(library); } // Parse the IMPORT_LOOKUP_TABLE for each imported library for (auto it = _imports.begin() ; it != _imports.end() ; ++it) { int ilt_offset; if ((*it)->first->OriginalFirstThunk != 0) { ilt_offset = _rva_to_offset((*it)->first->OriginalFirstThunk); } else { // Some packed executables use FirstThunk and set OriginalFirstThunk to 0. ilt_offset = _rva_to_offset((*it)->first->FirstThunk); } if (!ilt_offset || fseek(f, ilt_offset, SEEK_SET)) { PRINT_ERROR << "Could not reach an IMPORT_LOOKUP_TABLE." << std::endl; return true; } while (true) // We stop at the first NULL IMPORT_LOOKUP_TABLE { pimport_lookup_table import = boost::make_shared<import_lookup_table>(); import->AddressOfData = 0; import->Hint = 0; // The field has a size of 8 for x64 PEs int size_to_read = (_ioh->Magic == nt::IMAGE_OPTIONAL_HEADER_MAGIC.at("PE32+") ? 8 : 4); if (size_to_read != fread(&(import->AddressOfData), 1, size_to_read, f)) { PRINT_ERROR << "Could not read the IMPORT_LOOKUP_TABLE." << std::endl; return true; } // Exit condition if (import->AddressOfData == 0) { break; } // Read the HINT/NAME TABLE if applicable. Check the most significant byte of AddressOfData to // see if the import is by name or ordinal. For PE32+, AddressOfData is a uint64. boost::uint64_t mask = (size_to_read == 8 ? 0x8000000000000000 : 0x80000000); if (!(import->AddressOfData & mask)) { // Import by name. Read the HINT/NAME table. For both PE32 and PE32+, its RVA is stored // in bits 30-0 of AddressOfData. unsigned int table_offset = _rva_to_offset(import->AddressOfData & 0x7FFFFFFF); if (table_offset == 0) { PRINT_ERROR << "Could not reach the HINT/NAME table." << std::endl; return true; } unsigned int saved_offset = ftell(f); if (saved_offset == -1 || fseek(f, table_offset, SEEK_SET) || 2 != fread(&(import->Hint), 1, 2, f)) { PRINT_ERROR << "Could not read a HINT/NAME hint." << std::endl; return true; } import->Name = utils::read_ascii_string(f); //TODO: Demangle the import name // Go back to the import lookup table. if (fseek(f, saved_offset, SEEK_SET)) { return true; } } (*it)->second.push_back(import); } } return true; }