HMODULE CRemoteLoader::LoadLibraryByPathA( PCHAR Path )
{
	WCHAR Module[ MAX_PATH ] = { 0 };

	mbstowcs( Module, Path, MAX_PATH );

	DebugShout( "[LoadLibraryByPathA] ( %S <- %s )", Module, Path );

	return LoadLibraryByPathW( Module );
}
HMODULE CRemoteLoader::LoadLibraryByPathIntoMemoryW( PWCHAR Path, BOOL PEHeader )
{
	CHAR PathAnsi[ MAX_PATH ] = { 0 };

	wcstombs( PathAnsi, Path, MAX_PATH );

	DebugShout( "[LoadLibraryByPathIntoMemoryW]( %S -> %s )( 0x%X )", Path, PathAnsi, PEHeader );

	return LoadLibraryByPathIntoMemoryA( PathAnsi, PEHeader );
}
bool CRemoteCode::ExecuteRemoteThreadBuffer( remote_thread_buffer_t thread_data, bool async )
{
	unsigned long ulMemorySize = ( unsigned long )thread_data.size();

	void *vRemoteMemory = RemoteAllocateMemory( ulMemorySize );

	if( vRemoteMemory == NULL )
		return false;

	unsigned char *newBuffer = new unsigned char[ thread_data.size() ];

	for( int i = 0; i < (int)thread_data.size(); i++ )
	{
		memcpy( &newBuffer[i], &thread_data[i], sizeof( unsigned char ) );
	}

	BOOL bWriteProcess = WriteProcessMemory( m_hProcess, vRemoteMemory, newBuffer, thread_data.size(), NULL );

	if( bWriteProcess == FALSE )
		return false;

	DebugShout( "Memory written to process" );

	HANDLE hThreadHandle = CreateRemoteThreadInProcess( ( LPTHREAD_START_ROUTINE )vRemoteMemory, NULL );

	if( hThreadHandle == INVALID_HANDLE_VALUE )
		return false;

	DebugShout( "Remote Buffer Executed in process 0x%X", m_hProcess );

	if( async == true )
	{
		WaitForSingleObject( hThreadHandle, INFINITE );
	}

	RemoteFreeMemory( vRemoteMemory, ulMemorySize );

	memset( &m_CurrentInvokeInfo, 0, sizeof( m_CurrentInvokeInfo ) );

	m_CurrentRemoteThreadBuffer.clear();

	return true;
}
void CRemoteCode::PushParameter( parameter_type_t param_type, void *param )
{
	parameter_info_t pi;

	pi.ptype	= param_type;
	pi.pparam	= param;

	DebugShout( "Adding parameter to function [%i][0x%X]", pi.ptype, pi.pparam );

	m_CurrentInvokeInfo.params.push_back( pi );
}
BOOL CRemoteLoader::ProcessTlsEntries( PVOID BaseAddress, PVOID RemoteAddress )
{
	IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress );

	if( ImageNtHeaders == NULL ) 
		return FALSE;

	if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_TLS ].Size == 0 )
		return TRUE; // Success when there is no Tls Entries

	DebugShout( "[ProcessTlsEntries] Tls Data detected!" );

	IMAGE_TLS_DIRECTORY* TlsDirectory =
		( IMAGE_TLS_DIRECTORY* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_TLS ].VirtualAddress, BaseAddress );

	if( TlsDirectory == NULL )
		return TRUE; // Success when there is no Tls entries / broken data?

	DebugShout( "[ProcessTlsEntries] TlsDirectory (0x%X)", 
		TlsDirectory );

	if( TlsDirectory->AddressOfCallBacks == NULL )
		return TRUE; // Success when there is no Tls entries / broken data?

	DebugShout( "[ProcessTlsEntries] TlsDirectory->AddressOfCallBacks (0x%X)", 
		TlsDirectory->AddressOfCallBacks );

	PIMAGE_TLS_CALLBACK TLSCallbacks[ 0xFF ];

	if( ReadProcessMemory( GetProcess(), ( LPCVOID ) TlsDirectory->AddressOfCallBacks, TLSCallbacks, sizeof( TLSCallbacks ), NULL ) == FALSE )
	{
		DebugShout( "[ProcessTlsEntries] Failed ReadProcessMemory" );

		return FALSE;
	}

	BOOL SuccessValue = TRUE;

	for( int i = 0; TLSCallbacks[i]; i++ )
	{
		DebugShout( "[ProcessTlsEntries] TLSCallbacks[%i] = 0x%X (0x%X)", i, TLSCallbacks[i], RemoteAddress );

		// As a consequence of the relocation stuff mentioned above, pCallbacks[i] is already fixed

		if( CallEntryPoint( RemoteAddress, ( FARPROC ) TLSCallbacks[i] ) == false )
		{
			DebugShout( "[ProcessTlsEntries] Failed to execute Tls Entry [%i]", i );
		}
		else
		{
			DebugShout( "[ProcessTlsEntries] Called Tls Callback (0x%X)", TLSCallbacks[i] );
		}
	}

	return SuccessValue;
}
BOOL CRemoteLoader::ProcessSection( BYTE* Name, PVOID BaseAddress, PVOID RemoteAddress, ULONG RawData, ULONG VirtualAddress, ULONG RawSize, ULONG VirtualSize, ULONG ProtectFlag )
{
	DebugShout( "[ProcessSection] ProcessSection( %s, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X )",
		Name, BaseAddress, RemoteAddress, RawData, VirtualAddress, RawSize, VirtualSize, ProtectFlag );

	HANDLE hProcess = GetProcess();

	if( hProcess == INVALID_HANDLE_VALUE )
	{
		hProcess = GetCurrentProcess();
	}

	if( WriteProcessMemory( hProcess,
		MakePtr( PVOID, RemoteAddress, VirtualAddress ),
		MakePtr( PVOID, BaseAddress, RawData ),
		RawSize,
		NULL ) == FALSE )
	{
		DebugShout( "[ProcessSection] Failed to write memory for (%s) -> (%s)", Name, LastErrorString() );

		return FALSE;
	}

	DWORD dwOldProtect = NULL;

	if( VirtualProtectEx( hProcess,
		MakePtr( PVOID, RemoteAddress, VirtualAddress ),
		VirtualSize,
		ProtectFlag,
		&dwOldProtect ) == FALSE )
	{
		DebugShout( "[ProcessSection] Failed to protect memory for (%s) -> (%s)", Name, LastErrorString() );

		return FALSE;
	}

	return TRUE;
}
HMODULE CRemoteLoader::LoadLibraryByPathIntoMemoryA( PCHAR Path, BOOL PEHeader )
{
	HMODULE hReturnValue = NULL;

	DebugShout( "[LoadLibraryByPathIntoMemoryA] %s (0x%X)", Path, PEHeader );

	ModuleFile File = InitModuleFile( Path );

	if( File.IsValid() == FALSE )
	{
		DebugShout( "[LoadLibraryByPathIntoMemoryA] Failed to open file handle!" );

		return NULL;
	}

	hReturnValue = LoadLibraryFromMemory( File.Buffer, File.Size, PEHeader, Path );

	if( FreeModuleFile( File ) == FALSE )
	{
		DebugShout( "[LoadLibraryByPathIntoMemoryA] Failed to free file handle..." );
	}

	return hReturnValue;
}
void CRemoteCode::PushAllParameters( bool right_to_left )
{
	if( m_CurrentInvokeInfo.params.size() == 0 )
		return;

	DebugShout( "Parameters for function [%i]", m_CurrentInvokeInfo.params.size() );

	vector<parameter_info_t> currentParams = m_CurrentInvokeInfo.params;
	vector<parameter_info_t> pushOrder;

	if( right_to_left == false )
	{
		//left-to-right
		for( int i = 0; i < (int)m_CurrentInvokeInfo.params.size(); i++ )
		{
			pushOrder.push_back( m_CurrentInvokeInfo.params.at( i ) );

			DebugShout( "Parameter found [%i][%i]", i, m_CurrentInvokeInfo.params.at( i ).ptype );
		}
	}
	else
	{
		//right-to-left
		if( m_CurrentInvokeInfo.params.size() == 1 )
		{
			pushOrder.push_back( m_CurrentInvokeInfo.params.at( 0 ) );
		}
		else
		{
			int iBegin = (int)m_CurrentInvokeInfo.params.size() - 1;

			while( iBegin != -1 )
			{
				pushOrder.push_back( m_CurrentInvokeInfo.params.at( iBegin ) );

				DebugShout( "Parameter found [%i][%s]", iBegin, ParameterTypeToString( m_CurrentInvokeInfo.params.at( iBegin ).ptype ).c_str() );

				iBegin--;
			}
		}
	}

	for( int p = 0; p < (int)pushOrder.size(); p++ )
	{
		parameter_info_t *paraminfo = &pushOrder[p];

		if( paraminfo == NULL )
			continue;

		DebugShout( "Function Iter [%i]", p );
		DebugShout( "Function Parameter [%s]", ParameterTypeToString( paraminfo->ptype ).c_str() );

		if( paraminfo->pparam == NULL )
		{
			AddByteToBuffer( 0x68 );
			AddLongToBuffer( 0 );

			continue;
		}

		switch( paraminfo->ptype )
		{
			case PARAMETER_TYPE_SHORT:
			case PARAMETER_TYPE_POINTER:
			case PARAMETER_TYPE_INT:
			case PARAMETER_TYPE_FLOAT:
				{
					if( paraminfo->pparam )
					{
						unsigned long ulParam = *(unsigned long *)paraminfo->pparam;
	
						AddByteToBuffer( 0x68 );
						AddLongToBuffer( ulParam );
					}
					else
					{
						//if it is PARAMETER_TYPE_POINTER with a NULL pointer
						//we don't want to crash

						AddByteToBuffer( 0x68 );
						AddLongToBuffer( NULL );
					}

					break;
				}
			case PARAMETER_TYPE_BYTE:
				{
					unsigned char ucParam = *(unsigned char *)paraminfo->pparam;
	
					AddByteToBuffer( 0x6A );
					AddByteToBuffer( ucParam );
	
					break;
				}
			case PARAMETER_TYPE_BOOL:
				{
					bool bParam = *(bool *)paraminfo->pparam;
	
					unsigned char ucParam = (bParam) ? 1 : 0;
				
					AddByteToBuffer( 0x6A );
					AddByteToBuffer( ucParam );
	
					break;
				}
			case PARAMETER_TYPE_STRING:
				{
					char *szParameter		= (char *)paraminfo->pparam;

					void *AllocatedString	= CommitMemory( szParameter, strlen( szParameter ) + 1 );
	
					if( AllocatedString == NULL )
					{
						DebugShout( "NULL Allocated ANSI string pointer...." );

						continue; //bad beans
					}

					DebugShout( "Allocated string pointer at [0x%X]", AllocatedString );

					AddByteToBuffer( 0x68 );
					AddLongToBuffer( ( unsigned long ) AllocatedString );
	
					break;
				}
			case PARAMETER_TYPE_WSTRING:
				{
					wchar_t *szParameter	= (wchar_t *)paraminfo->pparam;

					void *AllocatedString	= CommitMemory( szParameter, (wcslen( szParameter ) * 2) + 1 );

					if( AllocatedString == NULL )
					{
						DebugShout( "NULL Allocated UNICODE string pointer...." );

						continue; //bad beans
					}

					AddByteToBuffer( 0x68 );
					AddLongToBuffer((unsigned long)AllocatedString);
	
					break;
				}
			default:
				{
					DebugShout( "Unable to locate parameter type %i", paraminfo->ptype );
	
					break;
				}
		}
	}
}
void CRemoteCode::AddByteToBuffer( unsigned char in )
{
	DebugShout( "Byte opcode added to buffer: 0x%02X", in );

	m_CurrentRemoteThreadBuffer.push_back( in );
}
HMODULE CRemoteLoader::LoadLibraryFromMemory( PVOID BaseAddress, DWORD SizeOfModule, BOOL PEHeader, PCHAR OptionalPath )
{
	DebugShout( "[LoadLibraryFromMemory] BaseAddress (0x%X) - SizeOfModule (0x%X)", BaseAddress, SizeOfModule );

	IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress );

	if( ImageNtHeaders == NULL )
	{
		DebugShout( "[LoadLibraryFromMemory] Invalid Image: No IMAGE_NT_HEADERS" );

		return NULL;
	}

	DebugShout( "[LoadLibraryFromMemory] SizeOfImage (0x%X)", ImageNtHeaders->OptionalHeader.SizeOfImage );

	if( ImageNtHeaders->FileHeader.NumberOfSections == 0 )
	{
		DebugShout( "[LoadLibraryFromMemory] Invalid Image: No Sections" );

		return NULL;
	}

	if( ( ImageNtHeaders->OptionalHeader.ImageBase % 4096 ) != 0 )
	{
		DebugShout( "[LoadLibraryFromMemory] Invalid Image: Not Page Aligned" );
		
		return NULL;
	}

	if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ].Size )
	{
		if( ImageDirectoryEntryToData( BaseAddress, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ) )
		{
			DebugShout( "[LoadLibraryFromMemory] This method is not supported for Managed executables!" );

			return NULL;
		}
	}

	DebugShout( "[LoadLibraryFromMemory] No COM/CLR data found!" );

	// SizeOfImage NOT the same as module size M**********R
	// http://www.youtube.com/watch?v=pele5vptVgc

	PVOID AllocatedRemoteMemory = RemoteAllocateMemory( ImageNtHeaders->OptionalHeader.SizeOfImage );

	if( AllocatedRemoteMemory == NULL )
	{
		DebugShout( "[LoadLibraryFromMemory] Failed to allocate remote memory for module!" );

		return NULL;
	}

	DebugShout( "[LoadLibraryFromMemory] Allocated remote module at [0x%X]!", AllocatedRemoteMemory );

	if( ProcessImportTable( BaseAddress, AllocatedRemoteMemory, OptionalPath ) == FALSE )
	{
		DebugShout( "[LoadLibraryFromMemory] Failed to fix imports!" );

		return NULL;
	}

	DebugShout( "[LoadLibraryFromMemory] Fixed Imports!" );

	if( ProcessRelocations( BaseAddress, AllocatedRemoteMemory ) == FALSE )
	{
		DebugShout( "[LoadLibraryFromMemory] Failed to process relocations!" );

		RemoteFreeMemory( AllocatedRemoteMemory, SizeOfModule );

		return NULL;
	}

	DebugShout( "[LoadLibraryFromMemory] Fixed Relocations!" );

	if( ProcessSections( BaseAddress, AllocatedRemoteMemory, PEHeader ) == FALSE )
	{
		DebugShout( "[LoadLibraryFromMemory] Failed to process sections!" );
	}

	DebugShout( "[LoadLibraryFromMemory] Processed sections!" );

	if( ProcessTlsEntries( BaseAddress, AllocatedRemoteMemory ) == FALSE )
	{
		DebugShout( "[LoadModuleFromMemory] ProcessTlsEntries Failed!" );

		// we can also choose to continue here..

		return NULL;
	}

	DebugShout( "[LoadModuleFromMemory] Processed Tls Entries!" );

	if( ImageNtHeaders->OptionalHeader.AddressOfEntryPoint )
	{
		FARPROC DllEntryPoint = MakePtr( FARPROC, AllocatedRemoteMemory, ImageNtHeaders->OptionalHeader.AddressOfEntryPoint );

		DebugShout( "[LoadModuleFromMemory] DllEntrypoint = 0x%X", DllEntryPoint );

		if( CallEntryPoint( AllocatedRemoteMemory, DllEntryPoint ) == false )
		{
			DebugShout( "[LoadModuleFromMemory] Failed to execute remote thread buffer" );
		}
		else
		{
			DebugShout( "[LoadModuleFromMemory] Executed the remote thread buffer successfully [0x%X]", DllEntryPoint );
		}
	}
	else
	{
		DebugShout( "[LoadModuleFromMemory] AddressOfEntryPoint is NULL" );
	}

	DebugShout( "[LoadModuleFromMemory] Returning Pointer (0x%X)", AllocatedRemoteMemory );

	return ( HMODULE ) AllocatedRemoteMemory;
}
void CRemoteCode::PushCall( calling_convention_t cconv, FARPROC CallAddress )
{
	DebugShout( "PushCall [0x%X][0x%X]", cconv, CallAddress );

	int iFunctionBegin	= (int)m_CurrentInvokeInfo.params.size();

	m_CurrentInvokeInfo.calladdress = reinterpret_cast<unsigned long>( CallAddress );
	m_CurrentInvokeInfo.cconv		= cconv;

	switch( cconv )
	{
	case CCONV_CDECL:
		{
			DebugShout( "Entering __cdecl" );

			int iCalculateAddEsp = (iFunctionBegin * 4);

			PushAllParameters( true );

			AddByteToBuffer( MOV_EAX_VALUE );
			AddLongToBuffer( m_CurrentInvokeInfo.calladdress );
			AddByteToBuffer( CALL_EXTERNAL );
			AddByteToBuffer( 0xD0 );			//eax

			if( iCalculateAddEsp != 0 )
			{
				bool bUseByte = (iCalculateAddEsp <= 0xFF);

				if( bUseByte )
				{
					//add esp, [BYTE]
					AddByteToBuffer( 0x83 );
					AddByteToBuffer( 0xC4 );
					AddByteToBuffer((unsigned char)iCalculateAddEsp);
				}
				else
				{
					
					//add esp, [LONG]
					AddByteToBuffer( 0x81 );
					AddByteToBuffer( 0xC4 );
					AddLongToBuffer( iCalculateAddEsp );
				}
			}

			break;
		}
	case CCONV_STDCALL:
		{
			DebugShout( "Entering __stdcall" );

			PushAllParameters( true );

			AddByteToBuffer( MOV_EAX_VALUE );
			AddLongToBuffer( m_CurrentInvokeInfo.calladdress );
			AddByteToBuffer( CALL_EXTERNAL );
			AddByteToBuffer( 0xD0 );			//eax

			break;
		}
	case CCONV_THISCALL:
		{
			DebugShout( "Entering __thiscall" );

			if( iFunctionBegin == 0 ) //no params...
			{
				DebugShout( "No parameters passed for __thiscall, requires at least one parameter (ECX)" );

				break;
			}

			//first parameter of __thiscall is ALWAYS ECX. ALWAYS.
			//the parameter type should also be PARAMETER_TYPE_POINTER
			if( m_CurrentInvokeInfo.params[0].ptype != PARAMETER_TYPE_POINTER )
			{
				DebugShout( "\"THIS\" parameter type invalid [%i]", m_CurrentInvokeInfo.params[0].ptype );
			}

			void *pThis = m_CurrentInvokeInfo.params[0].pparam;

			if( pThis == NULL )
			{
				DebugShout( "\"THIS\" parameter NULL for __thiscall function (ECX)" );
			}

			AddByteToBuffer( 0x8B );
			AddByteToBuffer( 0x0D );
			AddLongToBuffer((unsigned long)pThis);

			//now we need to remove the first parameter from the vector, so when we execute the
			//parameter iteration function it is not included.....

			m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() );

			PushAllParameters( true );

			AddByteToBuffer( MOV_EAX_VALUE );
			AddLongToBuffer( m_CurrentInvokeInfo.calladdress );
			AddByteToBuffer( CALL_EXTERNAL );
			AddByteToBuffer( 0xD0 );			//eax

			break;
		}
	case CCONV_FASTCALL:
		{
			DebugShout( "Entering __fastcall" );
			
			if( iFunctionBegin == 0 )
			{
				PushCall( CCONV_STDCALL, CallAddress );

				return;
			}
			else if( iFunctionBegin == 1 )
			{
				unsigned long ulEdxParam = *(unsigned long *)m_CurrentInvokeInfo.params[0].pparam;

				AddByteToBuffer( 0xBA );
				AddLongToBuffer( ulEdxParam );

				m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() );

				PushCall( CCONV_STDCALL, CallAddress );

				return;
			}
			else
			{
				unsigned long ulEdxParam = *(unsigned long *)m_CurrentInvokeInfo.params[0].pparam;
				unsigned long ulEaxParam = *(unsigned long *)m_CurrentInvokeInfo.params[1].pparam;
				
				AddByteToBuffer( 0xBA );
				AddLongToBuffer( ulEdxParam );
				AddByteToBuffer( MOV_EAX_VALUE );
				AddLongToBuffer( ulEaxParam );

				m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() );
				m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() );

				PushAllParameters( true );

				AddByteToBuffer( 0xBB );
				AddLongToBuffer( m_CurrentInvokeInfo.calladdress );
				AddByteToBuffer( CALL_EXTERNAL );
				AddByteToBuffer( 0xD3 );		//ebx
			}

			break;
		}
	}

	//clear data
	m_CurrentInvokeInfo.params.clear();
	m_CurrentInvokeInfo.calladdress = NULL;
}
ModuleFile CRemoteLoader::InitModuleFile( PCHAR FileName )
{
	ModuleFile r;

	r.Buffer	= 0;
	r.Size		= 0;

	HANDLE hFile = CreateFileA(
		FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

	if( hFile == INVALID_HANDLE_VALUE )
	{
		DebugShout( "[InitModuleFile] CreateFileA Failed" );

		return r;
	}

	DebugShout( "[InitModuleFile] File opened" );

	if( GetFileAttributesA( FileName ) & FILE_ATTRIBUTE_COMPRESSED )
	{
		r.Size = GetCompressedFileSizeA( FileName, NULL );

		DebugShout( "[InitModuleFile] File is compressed!" );
	}
	else
	{
		r.Size = GetFileSize( hFile, NULL );
	}

	DebugShout( "[InitModuleFile] Size [0x%X]", r.Size );

	if( r.Size == 0 )
	{
		CloseHandle( hFile );

		return r;
	}

	unsigned char *AllocatedFile = ( unsigned char* ) VirtualAlloc( NULL, r.Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );

	if( AllocatedFile == NULL )
	{
		DebugShout( "[InitModuleFile] Failed to allocate buffer!" );

		r.Size = 0;

		CloseHandle( hFile );

		return r;
	}

	DebugShout( "[InitModuleFile] Buffer allocated" );

	DWORD NumberOfBytesRead = 0;

	if( ReadFile( hFile, AllocatedFile, r.Size, &NumberOfBytesRead, FALSE ) == FALSE )
	{
		DebugShout( "[InitModuleFile] Read file failed.." );

		r.Buffer	= 0;
		r.Size		= 0;
	}
	else
	{
		DebugShout( "[InitModuleFile] Read file complete (0x%X)", NumberOfBytesRead );

		r.Buffer = AllocatedFile;
	}

	DebugShout( "[InitModuleFile] Buffer [0x%X]", r.Buffer );

	CloseHandle( hFile );

	return r;
}
BOOL CRemoteLoader::ProcessSections( PVOID BaseAddress, PVOID RemoteAddress, BOOL MapPEHeader )
{
	IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress );

	if( ImageNtHeaders == NULL ) 
		return FALSE;

	// Write PE header

	if( MapPEHeader )
	{
		if( WriteProcessMemory( GetProcess(), RemoteAddress, BaseAddress, ImageNtHeaders->OptionalHeader.SizeOfHeaders, NULL ) == FALSE )
		{
			DebugShout( "[ProcessSections] Failed to map PE header!" );
		}
		else
		{
			DebugShout( "[ProcessSections] Mapped PE Header successfully!" );
		}
	}
	else
	{
		DebugShout( "[ProcessSections] PE Header mapping disabled, skipping." );
	}

	// Write individual sections

	PIMAGE_SECTION_HEADER ImageSectionHeader = ( PIMAGE_SECTION_HEADER )
		( ( ( ULONG_PTR ) &ImageNtHeaders->OptionalHeader ) + ImageNtHeaders->FileHeader.SizeOfOptionalHeader );

	for( DWORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++ )
	{
		ULONG Protection = GetSectionProtection( ImageSectionHeader[ i ].Characteristics );

		if( !_stricmp( ".reloc", ( CHAR* ) ImageSectionHeader[ i ].Name ) )
		{
			DebugShout( "[ProcessSections] Skipping \".reloc\" section." );

			continue; // NOPE
		}

		if( ProcessSection( 
			ImageSectionHeader[ i ].Name,
			BaseAddress,
			RemoteAddress,
			ImageSectionHeader[ i ].PointerToRawData,
			ImageSectionHeader[ i ].VirtualAddress,
			ImageSectionHeader[ i ].SizeOfRawData,
			ImageSectionHeader[ i ].Misc.VirtualSize,
			Protection ) == FALSE )
		{
			DebugShout( "[ProcessSections] Failed %s", ImageSectionHeader[ i ].Name );
		}
		else
		{
			DebugShout( "[ProcessSections] Success %s", ImageSectionHeader[ i ].Name );
		}
	}

	return TRUE;
}
HMODULE CRemoteLoader::LoadLibraryByPathW( PWCHAR Path )
{
	if( Path == NULL )
	{
		DebugShout( "[LoadLibraryByPathW] szString is NULL" );

		return NULL;
	}

	FARPROC RemoteLoadLibraryW = GetRemoteProcAddress( "kernel32.dll", "LoadLibraryW" );

	if( RemoteLoadLibraryW == NULL )
	{
		DebugShout( "[LoadLibraryByPathW] LoadLibraryW Resolve Failure" );

		return NULL;
	}

	DebugShout( "[LoadLibraryByPathW] LoadLibraryW = 0x%X", RemoteLoadLibraryW );

	PVOID ReturnPointerValue = RemoteAllocateMemory( sizeof( DWORD ) );

	PushUNICODEString( Path );

	PushCall( CCONV_STDCALL, RemoteLoadLibraryW );

	//mov ptr, eax
	AddByteToBuffer( 0xA3 );
	AddLongToBuffer( ( DWORD ) ReturnPointerValue );

	//xor eax, eax
	AddByteToBuffer( 0x33 );
	AddByteToBuffer( 0xC0 );

	//retn 4
	AddByteToBuffer( 0xC2 );
	AddByteToBuffer( 0x04 );
	AddByteToBuffer( 0x00 );

	if( ExecuteRemoteThreadBuffer( m_CurrentRemoteThreadBuffer, true ) == false )
	{
		DebugShout( "[LoadLibraryByPathW] ExecuteRemoteThreadBuffer failed" );

		RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) );

		return NULL;
	}

	DebugShout( "[LoadModuleByNameW] ExecuteRemoteThreadBuffer succeeded" );

	DWORD RemoteModuleHandle = 0;

	if( ReadProcessMemory( GetProcess(), ReturnPointerValue, &RemoteModuleHandle, sizeof( DWORD ), NULL ) == TRUE )
	{
		RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) );
	}
	else
	{
		RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) );

		if( RemoteModuleHandle == 0 )
		{
			RemoteModuleHandle = ( DWORD ) GetRemoteModuleHandleW( Path );
		}
	}

	return ( HMODULE ) RemoteModuleHandle;
}
BOOL CRemoteLoader::ProcessRelocations( PVOID BaseAddress, PVOID RemoteAddress )
{
	IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress );

	if( ImageNtHeaders == NULL )
		return FALSE;

	if( ImageNtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED )
	{
		DebugShout( "[ProcessRelocations] Relocations have been stripped from this executable, continuing.." );

		return TRUE;
	}
	else
	{
		DWORD ImageBaseDelta = MakeDelta( DWORD, RemoteAddress, ImageNtHeaders->OptionalHeader.ImageBase );

		DebugShout( "[ProcessRelocations] VirtualAddress (0x%X)",
			ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress );

		DWORD RelocationSize = ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].Size;

		DebugShout( "[ProcessRelocations] Relocation Size [0x%X]", RelocationSize );

		if( RelocationSize )
		{
			IMAGE_BASE_RELOCATION* RelocationDirectory = ( IMAGE_BASE_RELOCATION* ) 
				RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress, BaseAddress );

			if( RelocationDirectory )
			{
				DebugShout( "[ProcessRelocations] RelocationDirectory (0x%X)", RelocationDirectory );

				PVOID RelocationEnd = reinterpret_cast< PBYTE >( RelocationDirectory ) + RelocationSize;

				while( RelocationDirectory < RelocationEnd )
				{
					PBYTE RelocBase = static_cast< PBYTE >( RvaToPointer( RelocationDirectory->VirtualAddress, BaseAddress ) );

					DWORD NumRelocs = ( RelocationDirectory->SizeOfBlock - sizeof( IMAGE_BASE_RELOCATION ) ) / sizeof( WORD ); 

					PWORD RelocationData = reinterpret_cast< PWORD >( RelocationDirectory + 1 );

					DebugShout( "[ProcessRelocations] RelocationDirectory (0x%X)", RelocationDirectory );
					DebugShout( "[ProcessRelocations] RelocationData (0x%X)", RelocationData );

					 for( DWORD i = 0; i < NumRelocs; ++i, ++RelocationData )
					 {
						 if( ProcessRelocation( ImageBaseDelta, *RelocationData, RelocBase ) == FALSE )
						 {
							 DebugShout( "[ProcessRelocations] Unable to process relocation (%i)", i );
						 }
					 }

					RelocationDirectory = reinterpret_cast< PIMAGE_BASE_RELOCATION >( RelocationData );
				}
			}
			else
			{
				DebugShout( "[ProcessRelocations] Relocations have a size, but the pointer is invalid" );

				return FALSE;
			}
		}
		else
		{
			DebugShout( "[ProcessRelocations] Relocations have have not been found in this executable, continuing.." );

			return TRUE;
		}
	}

	return TRUE;
}
BOOL CRemoteLoader::ProcessRelocation( INT ImageBaseDelta, WORD Data, PBYTE RelocationBase )
{
	BOOL bReturn = TRUE;

	switch( IMR_RELTYPE( Data ) )
	{
	case IMAGE_REL_BASED_ABSOLUTE:
		{
			DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_ABSOLUTE" );

			break;
		}
	case IMAGE_REL_BASED_HIGH:
		{
			SHORT* Raw		= reinterpret_cast< SHORT* >( RelocationBase + IMR_RELOFFSET( Data ) );
			SHORT Backup	= *Raw;

			*Raw += HIWORD( ImageBaseDelta );

			DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_HIGH (0x%X) -> (0x%X)", 
				Backup, *Raw );

			break;
		}
	case IMAGE_REL_BASED_LOW:
		{
			SHORT* Raw		= reinterpret_cast< SHORT* >( RelocationBase + IMR_RELOFFSET( Data ) );
			SHORT Backup	= *Raw;

			*Raw += LOWORD( ImageBaseDelta );

			DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_LOW (0x%X) -> (0x%X)", 
				Backup, *Raw );

			break;
		}
	case IMAGE_REL_BASED_HIGHLOW:
		{
			DWORD32* Raw	= reinterpret_cast< DWORD32* >( RelocationBase + IMR_RELOFFSET( Data ) );
			DWORD32 Backup	= *Raw;

			*Raw += ImageBaseDelta;

			DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_HIGHLOW (0x%X) -> (0x%X)", 
				Backup, *Raw );

			break;
		}
	case IMAGE_REL_BASED_DIR64:
		{
			DWORD64* Raw	= reinterpret_cast< DWORD64* >( RelocationBase + IMR_RELOFFSET( Data ) );
			DWORD64 Backup	= *Raw;

			*Raw += ImageBaseDelta;

			DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_DIR64 (0x%X) -> (0x%X)", 
				Backup, *Raw );

			break;
		}
	case IMAGE_REL_BASED_HIGHADJ:
		{
			DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_HIGHADJ" );

			break;
		}
	default:
		{
			DebugShout( "[ProcessRelocation] UNKNOWN RELOCATION (0x%X)", IMR_RELTYPE( Data ) );

			bReturn = FALSE;

			break;
		}
	}

	return bReturn;
}
BOOL CRemoteLoader::ProcessImportTable( PVOID BaseAddress, PVOID RemoteAddress, PCHAR OptionalPath )
{
	IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress );

	if( ImageNtHeaders == NULL )
		return FALSE;

	if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].Size )
	{
		IMAGE_IMPORT_DESCRIPTOR* ImageImportDescriptor = ( IMAGE_IMPORT_DESCRIPTOR* )
			RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].VirtualAddress, BaseAddress );

		if( ImageImportDescriptor )
		{
			for( ; ImageImportDescriptor->Name; ImageImportDescriptor++ )
			{
				PCHAR ModuleName = ( PCHAR ) RvaToPointer( ImageImportDescriptor->Name, BaseAddress );

				if( ModuleName == NULL )
				{
					DebugShout( "[ProcessImportTable] Module name for entry NULL" );

					continue;
				}

				DebugShout( "[ProcessImportTable] Module Name [%s]", ModuleName );

				HMODULE ModuleBase = GetRemoteModuleHandleA( ModuleName );

				if( ModuleBase == NULL )
				{
					ModuleBase = LoadLibraryByPathA( ModuleName );
				}

				if( ModuleBase == NULL )
				{
					DebugShout( "[ProcessImportTable] Failed to obtain module handle [%s]", ModuleName );

					continue;
				}

				IMAGE_THUNK_DATA *ImageThunkData	= NULL;
				IMAGE_THUNK_DATA *ImageFuncData		= NULL;

				if( ImageImportDescriptor->OriginalFirstThunk )
				{
					ImageThunkData	= ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->OriginalFirstThunk, BaseAddress );
					ImageFuncData	= ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress );
				}
				else
				{
					ImageThunkData	= ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress );
					ImageFuncData	= ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress );
				}

				
				if( ImageThunkData == NULL )
				{
					DebugShout( "[ProcessImportTable] Image Thunk Data is NULL" );
				}

				if( ImageFuncData == NULL )
				{
					DebugShout( "[ProcessImportTable] Image Func Data is NULL" );
				}

				for( ; ImageThunkData->u1.AddressOfData; ImageThunkData++, ImageFuncData++ )
				{
					FARPROC FunctionAddress = NULL;

					if( IMAGE_SNAP_BY_ORDINAL( ImageThunkData->u1.Ordinal ) )
					{
						SHORT Ordinal = ( SHORT ) IMAGE_ORDINAL( ImageThunkData->u1.Ordinal );

						FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, Ordinal );

						DebugShout( "[ProcessImportTable] Processed (%s -> %i) -> (0x%X)", 
							ModuleName, Ordinal, FunctionAddress );

						if( this->GetProcess() == INVALID_HANDLE_VALUE )
						{
							DebugShout( "[ProcessImportTable] Normal Value (0x%X)",
								GetProcAddress( GetModuleHandleA( ModuleName ), ( LPCSTR ) Ordinal ) );
						}
					}
					else
					{
						IMAGE_IMPORT_BY_NAME* ImageImportByName = ( IMAGE_IMPORT_BY_NAME* )
							RvaToPointer( *( DWORD* ) ImageThunkData, BaseAddress );

						PCHAR NameOfImport = ( PCHAR ) ImageImportByName->Name;

						FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, NameOfImport );

						DebugShout( "[ProcessImportTable] Processed (%s -> %s) -> (0x%X)", 
							ModuleName, NameOfImport, FunctionAddress );

						if( this->GetProcess() == INVALID_HANDLE_VALUE )
						{
							DebugShout( "[ProcessImportTable] Normal Value (0x%X)",
								GetProcAddress( GetModuleHandleA( ModuleName ), NameOfImport ) );
						}
					}

					ImageFuncData->u1.Function = ( DWORD ) FunctionAddress;
				}
			}

			return TRUE;
		}
		else
		{
			DebugShout( "[ProcessImportTable] Size of table confirmed but pointer to data invalid!" );

			return FALSE;
		}
	}
	else
	{
		DebugShout( "[ProcessImportTable] No Imports" );

		return TRUE;
	}

	return FALSE;
}