From e161a5a23368b3a5138af0685d846a66259fcb67 Mon Sep 17 00:00:00 2001
From: rukaimi <rukaimi@985867f9-ca9c-e1f6-822d-e8a4186388af>
Date: Wed, 12 Sep 2012 20:09:13 +0000
Subject: [PATCH] 1. Added new option for import rebuilder 2. Minor bugfixes

---
 pe_lib/pe_32_64.cpp   | 176 +++++++++++++++++++++++++++++++++++-------
 pe_lib/pe_base.cpp    |  27 +++++--
 pe_lib/pe_base.h      |  15 +++-
 pe_lib/pe_exception.h |   2 +-
 4 files changed, 183 insertions(+), 37 deletions(-)

diff --git a/pe_lib/pe_32_64.cpp b/pe_lib/pe_32_64.cpp
index 64fa7de..cbcf194 100644
--- a/pe_lib/pe_32_64.cpp
+++ b/pe_lib/pe_32_64.cpp
@@ -671,7 +671,7 @@ const pe_base::image_directory pe<PEClassType>::rebuild_imports(const imported_f
 	//Check if import_section is last one. If it's not, check if there's enough place for import data
 	if(&import_section != &*(sections_.end() - 1) && 
 		(import_section.empty() || align_up(import_section.get_size_of_raw_data(), get_file_alignment()) < needed_size + import_settings.get_offset_from_section_start()))
-		throw pe_exception("Insufficient space for import directory", pe_exception::insuffisient_space);
+		throw pe_exception("Insufficient space for import directory", pe_exception::insufficient_space);
 
 	std::string& raw_data = import_section.get_raw_data();
 
@@ -695,9 +695,20 @@ const pe_base::image_directory pe<PEClassType>::rebuild_imports(const imported_f
 		IMAGE_IMPORT_DESCRIPTOR descr = {0};
 		descr.TimeDateStamp = (*it).get_timestamp(); //Restore timestamp
 		descr.Name = rva_from_section_offset(import_section, current_string_pointer); //Library name RVA
-		
-		//If we should save IATs for current import descriptor
+
+		//If we should save IAT for current import descriptor
 		bool save_iats_for_this_descriptor = import_settings.save_iat_and_original_iat_rvas() && (*it).get_rva_to_iat() != 0;
+		//If we should write original IAT
+		bool write_original_iat = (!save_iats_for_this_descriptor && import_settings.build_original_iat()) || import_settings.fill_missing_original_iats();
+
+		//If we should rewrite saved original IAT for current import descriptor (without changing its position)
+		bool rewrite_saved_original_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && import_settings.build_original_iat();
+		//If we should rewrite saved IAT for current import descriptor (without changing its position)
+		bool rewrite_saved_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && (*it).get_rva_to_iat() != 0;
+
+		//Helper values if we're rewriting existing IAT or orig.IAT
+		DWORD original_first_thunk = 0;
+		DWORD first_thunk = 0;
 
 		if(save_iats_for_this_descriptor)
 		{
@@ -708,6 +719,20 @@ const pe_base::image_directory pe<PEClassType>::rebuild_imports(const imported_f
 				descr.OriginalFirstThunk = import_settings.build_original_iat() ? (*it).get_rva_to_original_iat() : 0;
 			
 			descr.FirstThunk = (*it).get_rva_to_iat();
+
+			original_first_thunk = descr.OriginalFirstThunk;
+			first_thunk = descr.FirstThunk;
+
+			if(rewrite_saved_original_iat)
+			{
+				if((*it).get_rva_to_original_iat())
+					write_original_iat = true;
+				else
+					rewrite_saved_original_iat = false;
+			}
+
+			if(rewrite_saved_iat)
+				save_iats_for_this_descriptor = false;
 		}
 		else
 		{
@@ -728,9 +753,6 @@ const pe_base::image_directory pe<PEClassType>::rebuild_imports(const imported_f
 		const import_library::imported_list& funcs = (*it).get_imported_functions();
 		for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f)
 		{
-			//If we must write original IAT
-			bool write_original_iat = (!save_iats_for_this_descriptor && import_settings.build_original_iat()) || import_settings.fill_missing_original_iats();
-
 			if((*f).has_name()) //If function is imported by name
 			{
 				//Get RVA of IMAGE_IMPORT_BY_NAME
@@ -743,22 +765,59 @@ const pe_base::image_directory pe<PEClassType>::rebuild_imports(const imported_f
 						//We're creating original IATs - so we can write to IAT saved VA (because IMAGE_IMPORT_BY_NAME will be read
 						//by PE loader from original IAT)
 						typename PEClassType::BaseSize iat_value = static_cast<typename PEClassType::BaseSize>((*f).get_iat_va());
-						memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
+
+						if(rewrite_saved_iat)
+						{
+							if(section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value))
+								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+							memcpy(section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value));
+
+							first_thunk += sizeof(iat_value);
+						}
+						else
+						{
+							memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
+							current_pos_for_iat += sizeof(rva_of_named_import);
+						}
 					}
 					else
 					{
 						//Else - write to IAT RVA of IMAGE_IMPORT_BY_NAME
-						memcpy(&raw_data[current_pos_for_iat], &rva_of_named_import, sizeof(rva_of_named_import));
+						if(rewrite_saved_iat)
+						{
+							if(section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import))
+								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+							memcpy(section_data_from_rva(first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import));
+
+							first_thunk += sizeof(rva_of_named_import);
+						}
+						else
+						{
+							memcpy(&raw_data[current_pos_for_iat], &rva_of_named_import, sizeof(rva_of_named_import));
+							current_pos_for_iat += sizeof(rva_of_named_import);
+						}
 					}
-
-					current_pos_for_iat += sizeof(rva_of_named_import);
 				}
 
 				if(write_original_iat)
 				{
-					//We're creating original IATs
-					memcpy(&raw_data[current_pos_for_original_iat], &rva_of_named_import, sizeof(rva_of_named_import));
-					current_pos_for_original_iat += sizeof(rva_of_named_import);
+					if(rewrite_saved_original_iat)
+					{
+						if(section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import))
+							throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);
+
+						memcpy(section_data_from_rva(original_first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import));
+
+						original_first_thunk += sizeof(rva_of_named_import);
+					}
+					else
+					{
+						//We're creating original IATs
+						memcpy(&raw_data[current_pos_for_original_iat], &rva_of_named_import, sizeof(rva_of_named_import));
+						current_pos_for_original_iat += sizeof(rva_of_named_import);
+					}
 				}
 
 				//Write IMAGE_IMPORT_BY_NAME (WORD hint + string function name)
@@ -780,34 +839,97 @@ const pe_base::image_directory pe<PEClassType>::rebuild_imports(const imported_f
 						//We're creating original IATs - so we can wtire to IAT saved VA (because ordinal will be read
 						//by PE loader from original IAT)
 						typename PEClassType::BaseSize iat_value = static_cast<typename PEClassType::BaseSize>((*f).get_iat_va());
-						memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
+						if(rewrite_saved_iat)
+						{
+							if(section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value))
+								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+							memcpy(section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value));
+
+							first_thunk += sizeof(iat_value);
+						}
+						else
+						{
+							memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
+							current_pos_for_iat += sizeof(thunk_value);
+						}
 					}
 					else
 					{
 						//Else - write ordinal to IAT
-						memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
+						if(rewrite_saved_iat)
+						{
+							if(section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+								throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+							memcpy(section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+							first_thunk += sizeof(thunk_value);
+						}
+						else
+						{
+							memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
+						}
 					}
-
-					current_pos_for_iat += sizeof(thunk_value);
 				}
 
 				//We're writing ordinal to original IAT slot
 				if(write_original_iat)
 				{
-					memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value));
-					current_pos_for_original_iat += sizeof(thunk_value);
+					if(rewrite_saved_original_iat)
+					{
+						if(section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+							throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);
+
+						memcpy(section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+						original_first_thunk += sizeof(thunk_value);
+					}
+					else
+					{
+						memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value));
+						current_pos_for_original_iat += sizeof(thunk_value);
+					}
 				}
 			}
 		}
 
-		if((!save_iats_for_this_descriptor && import_settings.build_original_iat()) || import_settings.fill_missing_original_iats())
+		if(!save_iats_for_this_descriptor)
+		{
+			//Ending null thunks
+			typename PEClassType::BaseSize thunk_value = 0;
+
+			if(rewrite_saved_iat)
+			{
+				if(section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+					throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+				memcpy(section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+				first_thunk += sizeof(thunk_value);
+			}
+			else
+			{
+				memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
+				current_pos_for_iat += sizeof(thunk_value);
+			}
+		}
+
+		if(write_original_iat)
 		{
 			//Ending null thunks
 			typename PEClassType::BaseSize thunk_value = 0;
-			memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
-			current_pos_for_iat += sizeof(thunk_value);
 
-			if(import_settings.build_original_iat())
+			if(rewrite_saved_original_iat)
+			{
+				if(section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+					throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);
+
+				memcpy(section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+				original_first_thunk += sizeof(thunk_value);
+			}
+			else
 			{
 				memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value));
 				current_pos_for_original_iat += sizeof(thunk_value);
@@ -936,7 +1058,7 @@ const pe_base::image_directory pe<PEClassType>::rebuild_tls(const tls_info& info
 	//Check if tls_section is last one. If it's not, check if there's enough place for TLS data
 	if(&tls_section != &*(sections_.end() - 1) && 
 		(tls_section.empty() || align_up(tls_section.get_size_of_raw_data(), get_file_alignment()) < needed_size + offset_from_section_start))
-		throw pe_exception("Insufficient space for TLS directory", pe_exception::insuffisient_space);
+		throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space);
 
 	//Check raw data positions
 	if(info.get_raw_data_end_rva() < info.get_raw_data_start_rva() || info.get_index_rva() == 0)
@@ -996,7 +1118,7 @@ const pe_base::image_directory pe<PEClassType>::rebuild_tls(const tls_info& info
 			//Check if there's enough virtual space for it...
 			if(section_data_length_from_rva(info.get_raw_data_start_rva(), info.get_raw_data_start_rva(), section_data_virtual, true)
 				< info.get_raw_data_end_rva() - info.get_raw_data_start_rva())
-				throw pe_exception("Insufficient space for TLS raw data", pe_exception::insuffisient_space);
+				throw pe_exception("Insufficient space for TLS raw data", pe_exception::insufficient_space);
 			else
 				write_raw_data_size = available_raw_length; //We'll write just a part of full raw data
 		}
@@ -1025,11 +1147,11 @@ const pe_base::image_directory pe<PEClassType>::rebuild_tls(const tls_info& info
 		//Check if there's enough space to write callbacks TLS data...
 		if(section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_raw, true)
 			< needed_callback_size - sizeof(typename PEClassType::BaseSize) /* last zero element can be virtual only */)
-			throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insuffisient_space);
+			throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space);
 		
 		if(section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_virtual, true)
 			< needed_callback_size /* check here full virtual data length available */)
-			throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insuffisient_space);
+			throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space);
 
 		std::vector<typename PEClassType::BaseSize> callbacks_virtual_addresses;
 		callbacks_virtual_addresses.reserve(info.get_tls_callbacks().size() + 1 /* last null element */);
diff --git a/pe_lib/pe_base.cpp b/pe_lib/pe_base.cpp
index cef3238..1057fdf 100644
--- a/pe_lib/pe_base.cpp
+++ b/pe_lib/pe_base.cpp
@@ -1044,7 +1044,7 @@ void pe_base::read_pe(std::istream& file, bool read_bound_import_raw_data, bool
 
 			//If section raw data size is greater than virtual, fix it
 			last_raw_size = s.header_.SizeOfRawData;
-			if(s.header_.SizeOfRawData > s.header_.Misc.VirtualSize)
+			if(align_up(s.header_.SizeOfRawData, get_file_alignment()) > align_up(s.header_.Misc.VirtualSize, get_section_alignment()))
 				s.header_.SizeOfRawData = s.header_.Misc.VirtualSize;
 
 			//Check virtual and raw section sizes and addresses
@@ -2115,7 +2115,7 @@ const pe_base::image_directory pe_base::rebuild_exports(const export_info& info,
 	//Check if exports_section is last one. If it's not, check if there's enough place for exports data
 	if(&exports_section != &*(sections_.end() - 1) && 
 		(exports_section.empty() || align_up(exports_section.get_size_of_raw_data(), get_file_alignment()) < needed_size + offset_from_section_start))
-		throw pe_exception("Insufficient space for export directory", pe_exception::insuffisient_space);
+		throw pe_exception("Insufficient space for export directory", pe_exception::insufficient_space);
 
 	std::string& raw_data = exports_section.get_raw_data();
 
@@ -2254,7 +2254,8 @@ pe_base::import_rebuilder_settings::import_rebuilder_settings(bool set_to_pe_hea
 	save_iat_and_original_iat_rvas_(true),
 	fill_missing_original_iats_(false),
 	set_to_pe_headers_(set_to_pe_headers),
-	zero_directory_entry_iat_(auto_zero_directory_entry_iat)
+	zero_directory_entry_iat_(auto_zero_directory_entry_iat),
+	rewrite_iat_and_original_iat_contents_(false)
 {}
 
 //Returns offset from section start where import directory data will be placed
@@ -2276,6 +2277,14 @@ bool pe_base::import_rebuilder_settings::save_iat_and_original_iat_rvas() const
 	return save_iat_and_original_iat_rvas_;
 }
 
+//Returns true if Original import address and import address tables contents will be rewritten
+//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+//and save_iat_and_original_iat_rvas is true
+bool pe_base::import_rebuilder_settings::rewrite_iat_and_original_iat_contents() const
+{
+	return rewrite_iat_and_original_iat_contents_;
+}
+
 //Returns true if original missing IATs will be rebuilt
 //(only if IATs are saved)
 bool pe_base::import_rebuilder_settings::fill_missing_original_iats() const
@@ -2309,9 +2318,13 @@ void pe_base::import_rebuilder_settings::build_original_iat(bool enable)
 
 //Sets if Original import address and import address tables will not be rebuilt,
 //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
-void pe_base::import_rebuilder_settings::save_iat_and_original_iat_rvas(bool enable)
+void pe_base::import_rebuilder_settings::save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents)
 {
 	save_iat_and_original_iat_rvas_ = enable;
+	if(save_iat_and_original_iat_rvas_)
+		rewrite_iat_and_original_iat_contents_ = enable_rewrite_iat_and_original_iat_contents;
+	else
+		rewrite_iat_and_original_iat_contents_ = false;
 }
 
 //Sets if original missing IATs will be rebuilt
@@ -2642,7 +2655,7 @@ const pe_base::image_directory pe_base::rebuild_relocations(const relocation_tab
 	//Check if reloc_section is last one. If it's not, check if there's enough place for relocations data
 	if(&reloc_section != &*(sections_.end() - 1) && 
 		(reloc_section.empty() || align_up(reloc_section.get_size_of_raw_data(), get_file_alignment()) < needed_size + offset_from_section_start))
-		throw pe_exception("Insufficient space for relocations directory", pe_exception::insuffisient_space);
+		throw pe_exception("Insufficient space for relocations directory", pe_exception::insufficient_space);
 
 	std::string& raw_data = reloc_section.get_raw_data();
 
@@ -3695,7 +3708,7 @@ const pe_base::image_directory pe_base::rebuild_resources(resource_directory& in
 	//Check if exports_section is last one. If it's not, check if there's enough place for resource data
 	if(&resources_section != &*(sections_.end() - 1) && 
 		(resources_section.empty() || align_up(resources_section.get_size_of_raw_data(), get_file_alignment()) < needed_size + offset_from_section_start))
-		throw pe_exception("Insufficient space for resource directory", pe_exception::insuffisient_space);
+		throw pe_exception("Insufficient space for resource directory", pe_exception::insufficient_space);
 
 	std::string& raw_data = resources_section.get_raw_data();
 
@@ -5106,7 +5119,7 @@ void pe_base::recalculate_section_sizes(section& s)
 	}
 
 	//Can occur only for last section
-	if(align_up(s.get_virtual_size(), get_section_alignment()) < s.get_size_of_raw_data())
+	if(align_up(s.get_virtual_size(), get_section_alignment()) < align_up(s.get_size_of_raw_data(), get_file_alignment()))
 		set_section_virtual_size(s, align_up(s.get_size_of_raw_data(), get_section_alignment())); //Recalculate section virtual size
 }
 
diff --git a/pe_lib/pe_base.h b/pe_lib/pe_base.h
index 35e5336..f218be0 100644
--- a/pe_lib/pe_base.h
+++ b/pe_lib/pe_base.h
@@ -12,7 +12,7 @@
 
 //Please don't remove this information from header
 //PE Library (c) DX 2011 - 2012, http://kaimi.ru
-//Version: 0.1.2
+//Version: 0.1.3
 //Free to use, modify and distribute
 
 // == more important ==
@@ -838,9 +838,15 @@ public: //IMPORTS
 		DWORD get_offset_from_section_start() const;
 		//Returns true if Original import address table (IAT) will be rebuilt
 		bool build_original_iat() const;
+
 		//Returns true if Original import address and import address tables will not be rebuilt,
 		//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
 		bool save_iat_and_original_iat_rvas() const;
+		//Returns true if Original import address and import address tables contents will be rewritten
+		//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+		//and save_iat_and_original_iat_rvas is true
+		bool rewrite_iat_and_original_iat_contents() const;
+
 		//Returns true if original missing IATs will be rebuilt
 		//(only if IATs are saved)
 		bool fill_missing_original_iats() const;
@@ -849,6 +855,7 @@ public: //IMPORTS
 		//Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
 		bool zero_directory_entry_iat() const;
 
+
 	public: //Setters
 		//Sets offset from section start where import directory data will be placed
 		void set_offset_from_section_start(DWORD offset);
@@ -856,7 +863,10 @@ public: //IMPORTS
 		void build_original_iat(bool enable);
 		//Sets if Original import address and import address tables will not be rebuilt,
 		//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
-		void save_iat_and_original_iat_rvas(bool enable);
+		//enable_rewrite_iat_and_original_iat_contents sets if Original import address and import address tables contents will be rewritten
+		//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+		//and save_iat_and_original_iat_rvas is true
+		void save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents = false);
 		//Sets if original missing IATs will be rebuilt
 		//(only if IATs are saved)
 		void fill_missing_original_iats(bool enable);
@@ -872,6 +882,7 @@ public: //IMPORTS
 		bool fill_missing_original_iats_;
 		bool set_to_pe_headers_;
 		bool zero_directory_entry_iat_;
+		bool rewrite_iat_and_original_iat_contents_;
 	};
 
 	//You can get all image imports with get_imported_functions() function
diff --git a/pe_lib/pe_exception.h b/pe_lib/pe_exception.h
index ddc9da6..7b05071 100644
--- a/pe_lib/pe_exception.h
+++ b/pe_lib/pe_exception.h
@@ -67,7 +67,7 @@ public:
 		stream_is_bad,
 
 		section_is_not_attached,
-		insuffisient_space,
+		insufficient_space,
 
 		cannot_rebase_relocations,
 
-- 
GitLab