FARPROC CRemoteLoader::GetRemoteProcAddress( PCHAR Module, SHORT Function )
{
	HMODULE hKernel32 = LoadLibraryA( "Kernel32.dll" );

	if( hKernel32 == NULL ) return NULL;

	DWORD GetProcAddressOffset = ( DWORD ) GetProcAddress - ( DWORD ) hKernel32;

	HMODULE hRemoteKernel32 = GetRemoteModuleHandleA( "Kernel32.dll" );

	if( hRemoteKernel32 == NULL ) return NULL;
	
	HMODULE hRemoteModule = GetRemoteModuleHandleA( Module );

	if( hRemoteModule == NULL ) return NULL;
	
	PVOID ReturnPointerValue = RemoteAllocateMemory( sizeof( DWORD ) );

	PushInt( ( INT ) hRemoteModule ); // HACKHACK: Why is this an int?
	PushInt( ( INT ) Function );
	PushCall( CCONV_STDCALL, ( FARPROC )( ( DWORD_PTR ) hRemoteKernel32 + ( DWORD_PTR ) GetProcAddressOffset ) );

	//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 )
	{
		RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) );

		return NULL;
	}

	DWORD ProcAddressRemote = 0;

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

		return ( FARPROC ) ProcAddressRemote;
	}
	
	RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) );

	return NULL;
}
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::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;
}
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;
}