//Get relocation list of pe file, supports one-word sized relocations only //If list_absolute_entries = true, IMAGE_REL_BASED_ABSOLUTE will be listed const relocation_table_list get_relocations(const pe_base& pe, bool list_absolute_entries) { relocation_table_list ret; //If image does not have relocations if(!pe.has_reloc()) return ret; //Check the length in bytes of the section containing relocation directory if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_basereloc), pe.get_directory_rva(image_directory_entry_basereloc), section_data_virtual, true) < sizeof(image_base_relocation)) throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); unsigned long current_pos = pe.get_directory_rva(image_directory_entry_basereloc); //First IMAGE_BASE_RELOCATION table image_base_relocation reloc_table = pe.section_data_from_rva<image_base_relocation>(current_pos, section_data_virtual, true); if(reloc_table.SizeOfBlock % 2) throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); unsigned long reloc_size = pe.get_directory_size(image_directory_entry_basereloc); unsigned long read_size = 0; //reloc_table.VirtualAddress is not checked (not so important) while(reloc_table.SizeOfBlock && read_size < reloc_size) { //Create relocation table relocation_table table; //Save RVA table.set_rva(reloc_table.VirtualAddress); if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock)) throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); //List all relocations for(unsigned long i = sizeof(image_base_relocation); i < reloc_table.SizeOfBlock; i += sizeof(uint16_t)) { relocation_entry entry(pe.section_data_from_rva<uint16_t>(current_pos + i, section_data_virtual, true)); if(list_absolute_entries || entry.get_type() != image_rel_based_absolute) table.add_relocation(entry); } //Save table ret.push_back(table); //Go to next relocation block if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock)) throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory); current_pos += reloc_table.SizeOfBlock; read_size += reloc_table.SizeOfBlock; if (read_size >= reloc_size) break; reloc_table = pe.section_data_from_rva<image_base_relocation>(current_pos, section_data_virtual, true); } return ret; }
//Returns version info property value //property_name - required property name //If throw_if_absent = true, will throw exception if property does not exist //If throw_if_absent = false, will return empty string if property does not exist const std::wstring version_info_viewer::get_property(const std::wstring& property_name, const std::wstring& translation, bool throw_if_absent) const { std::wstring ret; //If there're no strings if(strings_.empty()) { if(throw_if_absent) throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); return ret; } lang_string_values_map::const_iterator it = strings_.begin(); if(translation.empty()) { //If no translation was specified it = strings_.find(default_language_translation); //Find default translation table if(it == strings_.end()) //If there's no default translation table, take the first one it = strings_.begin(); } else { it = strings_.find(translation); //Find specified translation table if(it == strings_.end()) { if(throw_if_absent) throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); return ret; } } //Find value of the required property string_values_map::const_iterator str_it = (*it).second.find(property_name); if(str_it == (*it).second.end()) { if(throw_if_absent) throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist); return ret; } ret = (*str_it).second; return ret; }
//Simple relocations rebuilder //To keep PE file working, don't remove any of existing relocations in //relocation_table_list returned by a call to get_relocations() function //auto_strip_last_section - if true and relocations are placed in the last section, it will be automatically stripped //offset_from_section_start - offset from the beginning of reloc_section, where relocations data will be situated //If save_to_pe_header is true, PE header will be modified automatically const image_directory rebuild_relocations(pe_base& pe, const relocation_table_list& relocs, section& reloc_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section) { //Check that reloc_section is attached to this PE image if(!pe.section_attached(reloc_section)) throw pe_exception("Relocations section must be attached to PE file", pe_exception::section_is_not_attached); uint32_t current_reloc_data_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t)); uint32_t needed_size = current_reloc_data_pos - offset_from_section_start; //Calculate needed size for relocation tables uint32_t size_delta = needed_size; uint32_t start_reloc_pos = current_reloc_data_pos; //Enumerate relocation tables for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it) { needed_size += static_cast<uint32_t>((*it).get_relocations().size() * sizeof(uint16_t) /* relocations */ + sizeof(image_base_relocation) /* table header */); //End of each table will be DWORD-aligned if((start_reloc_pos + needed_size - size_delta) % sizeof(uint32_t)) needed_size += sizeof(uint16_t); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation } //Check if reloc_section is last one. If it's not, check if there's enough place for relocations data if(&reloc_section != &*(pe.get_image_sections().end() - 1) && (reloc_section.empty() || pe_utils::align_up(reloc_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + current_reloc_data_pos)) throw pe_exception("Insufficient space for relocations directory", pe_exception::insufficient_space); std::string& raw_data = reloc_section.get_raw_data(); //This will be done only if reloc_section is the last section of image or for section with unaligned raw length of data if(raw_data.length() < needed_size + current_reloc_data_pos) raw_data.resize(pe_utils::align_up(needed_size + current_reloc_data_pos, pe.get_file_alignment())); //Expand section raw data //Enumerate relocation tables for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it) { //Create relocation table header image_base_relocation reloc; reloc.VirtualAddress = (*it).get_rva(); const relocation_table::relocation_list& reloc_list = (*it).get_relocations(); reloc.SizeOfBlock = static_cast<uint32_t>(sizeof(image_base_relocation) + sizeof(uint16_t) * reloc_list.size()); if((reloc_list.size() * sizeof(uint16_t)) % sizeof(uint32_t)) //If we must align end of relocation table reloc.SizeOfBlock += sizeof(uint16_t); memcpy(&raw_data[current_reloc_data_pos], &reloc, sizeof(reloc)); current_reloc_data_pos += sizeof(reloc); //Enumerate relocations in table for(relocation_table::relocation_list::const_iterator r = reloc_list.begin(); r != reloc_list.end(); ++r) { //Save relocations uint16_t reloc_value = (*r).get_item(); memcpy(&raw_data[current_reloc_data_pos], &reloc_value, sizeof(reloc_value)); current_reloc_data_pos += sizeof(reloc_value); } if(current_reloc_data_pos % sizeof(uint32_t)) //If end of table is not DWORD-aligned { memset(&raw_data[current_reloc_data_pos], 0, sizeof(uint16_t)); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation current_reloc_data_pos += sizeof(uint16_t); } } image_directory ret(pe.rva_from_section_offset(reloc_section, start_reloc_pos), needed_size - size_delta); //Adjust section raw and virtual sizes pe.recalculate_section_sizes(reloc_section, auto_strip_last_section); //If auto-rewrite of PE headers is required if(save_to_pe_header) { pe.set_directory_rva(image_directory_entry_basereloc, ret.get_rva()); pe.set_directory_size(image_directory_entry_basereloc, ret.get_size()); pe.clear_characteristics_flags(image_file_relocs_stripped); pe.set_dll_characteristics(pe.get_dll_characteristics() | image_dllcharacteristics_dynamic_base); } return ret; }