From e75243f6aed362e4d871b4ffdd9c7ecf41da713c Mon Sep 17 00:00:00 2001
From: whh8b <whh8b@git.zephyr-software.com>
Date: Thu, 16 Jul 2015 04:31:09 +0000
Subject: [PATCH] Adding support for pcrel relocations.

---
 SConstruct        |   2 +-
 push64_relocs.cpp | 282 +++++++++++++++++++++++++++++++++++++---------
 push64_relocs.h   |   8 +-
 3 files changed, 231 insertions(+), 61 deletions(-)

diff --git a/SConstruct b/SConstruct
index e49ab6491..1ef882f00 100644
--- a/SConstruct
+++ b/SConstruct
@@ -28,7 +28,7 @@ else:
         env.Append(CFLAGS=" -O3")
         env.Append(CXXFLAGS=" -O3")
         env.Append(LINKFLAGS=" -O3")
-env.Append(CXXFLAGS=" -std=c++0x")
+#env.Append(CXXFLAGS=" -std=c++0x")
 
 # set 32/64 bit build properly
 #print  "env[64bit]="+str(env['do_64bit_build'])
diff --git a/push64_relocs.cpp b/push64_relocs.cpp
index 57746ad91..0d1c60440 100644
--- a/push64_relocs.cpp
+++ b/push64_relocs.cpp
@@ -37,6 +37,16 @@
 #include "push64_relocs.h"
 
 
+bool arg_has_relative(const ARGTYPE &arg)
+{
+	/* if it's relative memory, watch out! */
+	if(arg.ArgType&MEMORY_TYPE)
+		if(arg.ArgType&RELATIVE_)
+			return true;
+	
+	return false;
+}
+
 using namespace libIRDB;
 using namespace std;
 using namespace Zipr_SDK;
@@ -91,11 +101,97 @@ Relocation_t* Push64Relocs_t::FindPush64Relocation(Instruction_t* insn)
 	}
 	return NULL;
 }
+bool Push64Relocs_t::IsPcrelRelocation(Relocation_t *reloc)
+{
+	return (reloc->GetType().find("pcrel") != std::string::npos);
+}
+
+Relocation_t* Push64Relocs_t::FindPcrelRelocation(Instruction_t* insn)
+
+{
+	Instruction_t* first_slow_path_insn=NULL;
+	RelocationSet_t::iterator rit = insn->GetRelocations().begin();
+	for(rit; rit!=insn->GetRelocations().end(); rit++)
+	{
+		Relocation_t *reloc=*rit;
+		if (IsPcrelRelocation(reloc))
+			return reloc;
+	}
+	return NULL;
+}
 
 void Push64Relocs_t::HandlePush64Relocation(Instruction_t *insn, Relocation_t *reloc)
 {
-	std::unique_ptr<CallAddPair_t> reloc_pair(new CallAddPair_t(insn, insn->GetTarget()));
-	call_add_pairs.insert(std::move(reloc_pair));	
+	Instruction_t *add_insn = new Instruction_t;
+	AddressID_t *add_addr = new AddressID_t;
+	Instruction_t *jmp_insn = NULL;
+	virtual_offset_t next_addr = 0;
+	string databits = "";
+	Relocation_t *add_reloc = new Relocation_t;
+
+	plopped_relocs.insert(insn);	
+
+	jmp_insn = insn->GetFallthrough();
+	assert(jmp_insn);
+
+	next_addr = insn->GetAddress()->GetVirtualOffset() + insn->GetDataBits().length();
+
+	/*
+	 * Change the push64 to a call/add pair.
+	 */
+
+	/* 
+	 * Step 0: Add the add instruction and its address.
+	 */
+	add_addr->SetFileID(insn->GetAddress()->GetFileID());
+	add_insn->SetAddress(add_addr);
+	add_insn->SetFunction(insn->GetFunction());
+	m_firp.GetAddresses().insert(add_addr);
+	m_firp.GetInstructions().insert(add_insn);
+
+	/* 
+	 * Step 1: Change the push to a call 0.
+	 */
+	databits.resize(5);
+	databits[0] = 0xe8;
+	databits[1] = 0x00;
+	databits[2] = 0x00;
+	databits[3] = 0x00;
+	databits[4] = 0x00;
+	insn->SetDataBits(databits);
+	insn->SetTarget(add_insn); // Comment
+	insn->SetComment(insn->GetComment()+" Thunk part");
+		
+	/* 
+	 * Step 2: Create the add instruction.
+	 */
+	databits = "";
+	databits.resize(7);
+	databits[0]=0x81;
+	databits[1]=0x2c;	
+	databits[2]=0x24;
+	databits[3]=0xff;
+	databits[4]=0xff;
+	databits[5]=0xff;
+	databits[6]=0xff;
+	add_insn->SetDataBits(databits);
+
+	/*
+	 * Step 3: Put the relocation on the add instruction.
+	 */
+	add_reloc->SetOffset(next_addr);
+	add_reloc->SetType("add64");
+	add_insn->GetRelocations().insert(add_reloc);
+	m_firp.GetRelocations().insert(add_reloc);
+
+	if (m_opts.GetVerbose())
+		cout << "Adding an add/sub with reloc offset 0x" 
+		     << std::hex << add_reloc->GetOffset() 
+				 << endl;
+	/*
+	 * Step 4: Tell the add insn to fallthrough to the call.
+	 */
+	add_insn->SetFallthrough(jmp_insn);
 }
 
 void Push64Relocs_t::HandlePush64Relocs()
@@ -107,15 +203,22 @@ void Push64Relocs_t::HandlePush64Relocs()
 	InstructionSet_t::iterator iit = m_firp.GetInstructions().begin();
 	for(iit; iit!=m_firp.GetInstructions().end(); iit++)
 	{
-		Instruction_t& insn=*(*iit);
+		Instruction_t *insn=*iit;
 		insns++;
 
-		Relocation_t* reloc=FindPush64Relocation(&insn);
-		if(reloc)
+		Relocation_t* reloc=NULL;
+		if (reloc = FindPush64Relocation(insn))
 		{
 			if (m_opts.GetVerbose())
 				cout << "Found a Push64 relocation." << endl;
-			HandlePush64Relocation(&insn,reloc);
+			HandlePush64Relocation(insn,reloc);
+			handled++;
+		}
+		else if (reloc = FindPcrelRelocation(insn))
+		{
+			if (m_opts.GetVerbose())
+				cout << "Found a pcrel relocation." << endl;
+			plopped_relocs.insert(insn);
 			handled++;
 		}
 	}
@@ -128,66 +231,133 @@ void Push64Relocs_t::UpdatePush64Adds()
 {
 	if (m_opts.GetVerbose())
 		cout << "UpdatePush64Adds()" << endl;
-	CallAddPairs_t::iterator cap_it = call_add_pairs.begin();
-	for (cap_it; cap_it != call_add_pairs.end(); cap_it++)
+	InstructionSet_t::iterator insn_it = plopped_relocs.begin();
+	for (insn_it; insn_it != plopped_relocs.end(); insn_it++)
 	{
-		bool change_to_add = false;
-		RangeAddress_t call_addr = 0;
-		RangeAddress_t add_addr = 0;
-		int add_offset = 0;
-		uint32_t relocated_value = 0;
-		Instruction_t *call = NULL, *add = NULL;
-		CallAddPair_t *cap = cap_it->get();
-		Relocation_t *add_reloc = NULL;
-
-		call = cap->first;
-		add = cap->second;
-
-		call_addr = final_insn_locations[call];
-		add_addr = final_insn_locations[add];
-
-		if (call_addr == 0 || add_addr == 0)
+		Relocation_t *reloc = NULL;
+		Instruction_t *insn = *insn_it;
+		if (reloc = FindPush64Relocation(insn))
 		{
-			if (m_opts.GetVerbose())
-				cout << "Call/Add pair not plopped?" << endl;
-			continue;
-		}
+			bool change_to_add = false;
+			RangeAddress_t call_addr = 0;
+			RangeAddress_t add_addr = 0;
+			int add_offset = 0;
+			uint32_t relocated_value = 0;
+			Instruction_t *call = NULL, *add = NULL;
+			Relocation_t *add_reloc = NULL;
 
-		add_reloc = FindAdd64Relocation(add);
-		assert(add_reloc && "Add in Call/Add pair must have relocation.");
+			call = *insn_it;
+			add = call->GetTarget();
 
-		add_offset = add_reloc->GetOffset();
+			assert(call && add);
 
-		/*
-		 * Stupid call will push the NEXT instruction address.
-		 */
-		call_addr+=call->GetDataBits().length();
+			call_addr = final_insn_locations[call];
+			add_addr = final_insn_locations[add];
 
-		if (add_offset>call_addr)
-		{
-			change_to_add = true;
-			relocated_value = add_offset-call_addr;
+			if (call_addr == 0 || add_addr == 0)
+			{
+				if (m_opts.GetVerbose())
+					cout << "Call/Add pair not plopped?" << endl;
+				continue;
+			}
+
+			add_reloc = FindAdd64Relocation(add);
+			assert(add_reloc && "Add in Call/Add pair must have relocation.");
+
+			add_offset = add_reloc->GetOffset();
+
+			/*
+			 * Stupid call will push the NEXT instruction address.
+			 */
+			call_addr+=call->GetDataBits().length();
+
+			if (add_offset>call_addr)
+			{
+				change_to_add = true;
+				relocated_value = add_offset-call_addr;
+			}
+			else
+			{
+				relocated_value = call_addr-add_offset;
+			}
+
+			cout << "Relocating a(n) "<< ((change_to_add) ? "add":"sub") << " from " 
+			     << std::hex << call_addr 
+					 << " at "
+					 << std::hex << add_addr
+					 << endl
+			     << "Using 0x" << std::hex << relocated_value 
+			     << " as the updated offset." << endl
+					 << "Using 0x" << std::hex << add_offset 
+					 << " as the base offset." << endl;
+			if (change_to_add)
+			{
+				char add = (char)0x04;
+				m_memory_space.PlopBytes(add_addr+1, (const char*)&add, 1);
+			}
+			m_memory_space.PlopBytes(add_addr+3, (const char*)&relocated_value, 4);
 		}
-		else
+		else if (reloc = FindPcrelRelocation(insn))
 		{
-			relocated_value = call_addr-add_offset;
-		}
+			uint8_t memory_offset = 0;
+			int32_t existing_offset = 0;
+			int32_t new_offset = 0;
+			uint32_t insn_addr = 0;
+			int existing_offset_size = 0;
+			uint8_t *insn_bytes = NULL;
+			int insn_bytes_len = 0;
+			DISASM d;
+			ARGTYPE *arg=NULL;
+			
+			insn_addr = final_insn_locations[insn];
+			if (insn_addr == 0)
+			{
+				if (m_opts.GetVerbose())
+					cout << "Skipping unplopped Pcrel relocation." << endl;
+				continue;
+			}
+			assert(insn_addr != 0);
 
-		cout << "Relocating a(n) "<< ((change_to_add) ? "add":"sub") << " from " 
-		     << std::hex << call_addr 
-				 << " at "
-				 << std::hex << add_addr
-				 << endl
-		     << "Using 0x" << std::hex << relocated_value 
-		     << " as the updated offset." << endl
-				 << "Using 0x" << std::hex << add_offset 
-				 << " as the base offset." << endl;
-		if (change_to_add)
-		{
-			char add = (char)0x04;
-			m_memory_space.PlopBytes(add_addr+1, (const char*)&add, 1);
+			insn_bytes_len = sizeof(uint8_t)*insn->GetDataBits().length();
+			insn_bytes=(uint8_t*)malloc(insn_bytes_len);
+			memcpy(insn_bytes, insn->GetDataBits().c_str(), insn_bytes_len);
+
+			insn->Disassemble(d);
+
+			if(arg_has_relative(d.Argument1))
+				arg=&d.Argument1;
+			if(arg_has_relative(d.Argument2))
+				arg=&d.Argument2;
+			if(arg_has_relative(d.Argument3))
+				arg=&d.Argument3;
+
+			assert(arg);
+
+			memory_offset = arg->Memory.DisplacementAddr-d.EIP;
+			existing_offset_size = arg->Memory.DisplacementSize;
+			assert(memory_offset>=0 && memory_offset <=15 &&
+			      (existing_offset_size==1 || 
+			       existing_offset_size==2 || 
+						 existing_offset_size==4 || 
+						 existing_offset_size==8));
+
+			memcpy((uint8_t*)&existing_offset, 
+			       (uint8_t*)&insn_bytes[memory_offset], 
+						 existing_offset_size);
+
+			new_offset = existing_offset-insn_addr; 
+			if (m_opts.GetVerbose())
+				cout << "Relocating a pcrel relocation with 0x" 
+				     << std::hex << existing_offset
+						 << " existing offset at 0x" 
+						 << insn_addr << "." << endl
+						 << "Based on: " << d.CompleteInstr << endl
+						 << "New address: 0x" << std::hex << new_offset << endl;
+			
+			m_memory_space.PlopBytes(insn_addr+memory_offset,
+			                         (const char*)&new_offset,
+															 existing_offset_size);
 		}
-		m_memory_space.PlopBytes(add_addr+3, (const char*)&relocated_value, 4);
 	}
 }
 
diff --git a/push64_relocs.h b/push64_relocs.h
index ef9fa7098..71e1cf87e 100644
--- a/push64_relocs.h
+++ b/push64_relocs.h
@@ -31,9 +31,7 @@
 #ifndef nonce_relocs_h
 #define nonce_relocs_h
 
-typedef std::pair<Instruction_t*, Instruction_t*> CallAddPair_t;
-typedef std::set<std::unique_ptr<CallAddPair_t>> CallAddPairs_t;
-
+typedef std::set<Instruction_t*> InstructionPtrSet_t;
 class Push64Relocs_t : public Zipr_SDK::ZiprPluginInterface_t
 {
 	public:
@@ -71,6 +69,8 @@ class Push64Relocs_t : public Zipr_SDK::ZiprPluginInterface_t
 		void UpdatePush64Adds();
 
 		// helpers
+		bool IsPcrelRelocation(libIRDB::Relocation_t *reloc);
+		libIRDB::Relocation_t* FindPcrelRelocation(libIRDB::Instruction_t* insn);
 		bool IsAdd64Relocation(libIRDB::Relocation_t *reloc);
 		libIRDB::Relocation_t* FindAdd64Relocation(libIRDB::Instruction_t* insn);
 		bool IsPush64Relocation(libIRDB::Relocation_t *reloc);
@@ -85,7 +85,7 @@ class Push64Relocs_t : public Zipr_SDK::ZiprPluginInterface_t
 		Zipr_SDK::InstructionLocationMap_t &final_insn_locations;
 
 		// local data.
-		CallAddPairs_t call_add_pairs;
+		InstructionPtrSet_t plopped_relocs;
 
 };
 
-- 
GitLab