311 lines
12 KiB
C++
311 lines
12 KiB
C++
/*************************************************************************/
|
|
/* 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 <string.h>
|
|
#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<const image_bound_import_descriptor*>(&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<const image_bound_forwarder_ref*>(&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<const image_bound_import_descriptor*>(&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<uint32_t>((*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<uint32_t>((*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<uint16_t>(import.get_module_ref_list().size());
|
|
descriptor.OffsetModuleName = static_cast<uint16_t>(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<uint32_t>(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<uint16_t>(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<uint32_t>(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;
|
|
}
|
|
}
|