/*************************************************************************/ /* Copyright (c) 2015 dx, http://kaimi.ru */ /* */ /* Permission is hereby granted, free of charge, to any person */ /* obtaining a copy of this software and associated documentation */ /* files (the "Software"), to deal in the Software without */ /* restriction, including without limitation the rights to use, */ /* copy, modify, merge, publish, distribute, sublicense, and/or */ /* sell copies of the Software, and to permit persons to whom the */ /* Software is furnished to do so, subject to the following conditions: */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include #include "pe_bound_import.h" #include "utils.h" namespace pe_bliss { using namespace pe_win; //BOUND IMPORT //Default constructor bound_import_ref::bound_import_ref() :timestamp_(0) {} //Constructor from data bound_import_ref::bound_import_ref(const std::string& module_name, uint32_t timestamp) :module_name_(module_name), timestamp_(timestamp) {} //Returns imported module name const std::string& bound_import_ref::get_module_name() const { return module_name_; } //Returns bound import date and time stamp uint32_t bound_import_ref::get_timestamp() const { return timestamp_; } //Sets module name void bound_import_ref::set_module_name(const std::string& module_name) { module_name_ = module_name; } //Sets timestamp void bound_import_ref::set_timestamp(uint32_t timestamp) { timestamp_ = timestamp; } //Default constructor bound_import::bound_import() :timestamp_(0) {} //Constructor from data bound_import::bound_import(const std::string& module_name, uint32_t timestamp) :module_name_(module_name), timestamp_(timestamp) {} //Returns imported module name const std::string& bound_import::get_module_name() const { return module_name_; } //Returns bound import date and time stamp uint32_t bound_import::get_timestamp() const { return timestamp_; } //Returns bound references cound size_t bound_import::get_module_ref_count() const { return refs_.size(); } //Returns module references const bound_import::ref_list& bound_import::get_module_ref_list() const { return refs_; } //Adds module reference void bound_import::add_module_ref(const bound_import_ref& ref) { refs_.push_back(ref); } //Clears module references list void bound_import::clear_module_refs() { refs_.clear(); } //Returns module references bound_import::ref_list& bound_import::get_module_ref_list() { return refs_; } //Sets module name void bound_import::set_module_name(const std::string& module_name) { module_name_ = module_name; } //Sets timestamp void bound_import::set_timestamp(uint32_t timestamp) { timestamp_ = timestamp; } const bound_import_module_list get_bound_import_module_list(const pe_base& pe) { //Returned bound import modules list bound_import_module_list ret; //If image has no bound imports if(!pe.has_bound_import()) return ret; uint32_t bound_import_data_len = pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true); if(bound_import_data_len < pe.get_directory_size(image_directory_entry_bound_import)) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); const char* bound_import_data = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true); //Check read in "read_pe" function raw bound import data size if(bound_import_data_len < sizeof(image_bound_import_descriptor)) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //current bound_import_data_ in-string position unsigned long current_pos = 0; //first bound import descriptor //so, we're working with raw data here, no section helpers available const image_bound_import_descriptor* descriptor = reinterpret_cast(&bound_import_data[current_pos]); //Enumerate until zero while(descriptor->OffsetModuleName) { //Check module name offset if(descriptor->OffsetModuleName >= bound_import_data_len) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //Check module name for null-termination if(!pe_utils::is_null_terminated(&bound_import_data[descriptor->OffsetModuleName], bound_import_data_len - descriptor->OffsetModuleName)) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //Create bound import descriptor structure bound_import elem(&bound_import_data[descriptor->OffsetModuleName], descriptor->TimeDateStamp); //Check DWORDs if(descriptor->NumberOfModuleForwarderRefs >= pe_utils::max_dword / sizeof(image_bound_forwarder_ref) || !pe_utils::is_sum_safe(current_pos, 2 /* this descriptor and the next one */ * sizeof(image_bound_import_descriptor) + descriptor->NumberOfModuleForwarderRefs * sizeof(image_bound_forwarder_ref))) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //Move after current descriptor current_pos += sizeof(image_bound_import_descriptor); //Enumerate referenced bound import descriptors for(unsigned long i = 0; i != descriptor->NumberOfModuleForwarderRefs; ++i) { //They're just after parent descriptor //Check size of structure if(current_pos + sizeof(image_bound_forwarder_ref) > bound_import_data_len) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //Get IMAGE_BOUND_FORWARDER_REF pointer const image_bound_forwarder_ref* ref_descriptor = reinterpret_cast(&bound_import_data[current_pos]); //Check referenced module name if(ref_descriptor->OffsetModuleName >= bound_import_data_len) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //And its null-termination if(!pe_utils::is_null_terminated(&bound_import_data[ref_descriptor->OffsetModuleName], bound_import_data_len - ref_descriptor->OffsetModuleName)) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //Add referenced module to current bound import structure elem.add_module_ref(bound_import_ref(&bound_import_data[ref_descriptor->OffsetModuleName], ref_descriptor->TimeDateStamp)); //Move after referenced bound import descriptor current_pos += sizeof(image_bound_forwarder_ref); } //Check structure size if(current_pos + sizeof(image_bound_import_descriptor) > bound_import_data_len) throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory); //Move to next bound import descriptor descriptor = reinterpret_cast(&bound_import_data[current_pos]); //Save created descriptor structure and references ret.push_back(elem); } //Return result return ret; } //imports - bound imported modules list //imports_section - section where export directory will be placed (must be attached to PE image) //offset_from_section_start - offset from imports_section raw data start //save_to_pe_headers - if true, new bound import directory information will be saved to PE image headers //auto_strip_last_section - if true and bound imports are placed in the last section, it will be automatically stripped const image_directory rebuild_bound_imports(pe_base& pe, const bound_import_module_list& imports, section& imports_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) { //Check that exports_section is attached to this PE image if(!pe.section_attached(imports_section)) throw pe_exception("Bound import section must be attached to PE file", pe_exception::section_is_not_attached); uint32_t directory_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); uint32_t needed_size = sizeof(image_bound_import_descriptor) /* Ending null descriptor */; uint32_t needed_size_for_strings = 0; //Calculate needed size for bound import data for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it) { const bound_import& import = *it; needed_size += sizeof(image_bound_import_descriptor); needed_size_for_strings += static_cast((*it).get_module_name().length()) + 1 /* nullbyte */; const bound_import::ref_list& refs = import.get_module_ref_list(); for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it) { needed_size_for_strings += static_cast((*ref_it).get_module_name().length()) + 1 /* nullbyte */; needed_size += sizeof(image_bound_forwarder_ref); } } needed_size += needed_size_for_strings; //Check if imports_section is last one. If it's not, check if there's enough place for bound import data if(&imports_section != &*(pe.get_image_sections().end() - 1) && (imports_section.empty() || pe_utils::align_up(imports_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + directory_pos)) throw pe_exception("Insufficient space for bound import directory", pe_exception::insufficient_space); std::string& raw_data = imports_section.get_raw_data(); //This will be done only if imports_section is the last section of image or for section with unaligned raw length of data if(raw_data.length() < needed_size + directory_pos) raw_data.resize(needed_size + directory_pos); //Expand section raw data uint32_t current_pos_for_structures = directory_pos; uint32_t current_pos_for_strings = current_pos_for_structures + needed_size - needed_size_for_strings; for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it) { const bound_import& import = *it; image_bound_import_descriptor descriptor; descriptor.NumberOfModuleForwarderRefs = static_cast(import.get_module_ref_list().size()); descriptor.OffsetModuleName = static_cast(current_pos_for_strings - directory_pos); descriptor.TimeDateStamp = import.get_timestamp(); memcpy(&raw_data[current_pos_for_structures], &descriptor, sizeof(descriptor)); current_pos_for_structures += sizeof(descriptor); size_t length = import.get_module_name().length() + 1 /* nullbyte */; memcpy(&raw_data[current_pos_for_strings], import.get_module_name().c_str(), length); current_pos_for_strings += static_cast(length); const bound_import::ref_list& refs = import.get_module_ref_list(); for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it) { const bound_import_ref& ref = *ref_it; image_bound_forwarder_ref ref_descriptor = {0}; ref_descriptor.OffsetModuleName = static_cast(current_pos_for_strings - directory_pos); ref_descriptor.TimeDateStamp = ref.get_timestamp(); memcpy(&raw_data[current_pos_for_structures], &ref_descriptor, sizeof(ref_descriptor)); current_pos_for_structures += sizeof(ref_descriptor); length = ref.get_module_name().length() + 1 /* nullbyte */; memcpy(&raw_data[current_pos_for_strings], ref.get_module_name().c_str(), length); current_pos_for_strings += static_cast(length); } } //Adjust section raw and virtual sizes pe.recalculate_section_sizes(imports_section, auto_strip_last_section); image_directory ret(pe.rva_from_section_offset(imports_section, directory_pos), needed_size); //If auto-rewrite of PE headers is required if(save_to_pe_header) { pe.set_directory_rva(image_directory_entry_bound_import, ret.get_rva()); pe.set_directory_size(image_directory_entry_bound_import, ret.get_size()); } return ret; } }