#include "URedirection.h"

__declspec (naked) void ProcessEvent ()
{
	_asm push ebp						// Fix call stack

	_asm mov eax, [esp+4h]
	_asm mov pFunction, eax
	_asm mov eax, [esp+8h]
	_asm mov pParms, eax

	_asm pushad

	if (pFunction != NULL)
	{
		if (pFunction->FriendlyName == ENGINE_PlayerTick)
			// Process PlayerTick to plugins

		//if (pFunction->FriendlyName == ENGINE_PostRender)
			// Process PostRender to plugins

		if (pFunction->FriendlyName == ENGINE_ServerCallback)
		{
			INT SecType	 = ((ASecurity_eventServerCallback_Parms*)pParms)->SecType;
			FString Data = ((ASecurity_eventServerCallback_Parms*)pParms)->Data;

			GLog->Logf(L"URedirection::eventServerCallback : %i / %ls", SecType, Data);

			URedirection_Package* Package = PackageList;

			while (Package)
			{
				if (LastFile == Package->Filename)
				{
					GLog->Logf(L"ServerCallback - Replacing %ls", ((ASecurity_eventServerCallback_Parms*)pParms)->Data);
					//if (Package->Action == 2)
					//{
						if (((ASecurity_eventServerCallback_Parms*)pParms)->SecType == 0)
							((ASecurity_eventServerCallback_Parms*)pParms)->Data = FString::Printf(L"%ls%ls", Package->GUID, Package->QuickMD5);
						else
							((ASecurity_eventServerCallback_Parms*)pParms)->Data = Package->FullMD5;
					//}
				}
			}
		}
	}

	_asm popad

	_asm jmp dwJmp_ProcessEvent
}

__declspec (naked) void GetReferencers ()
{
	_asm add esp, 8h					// Fix call stack

	_asm pushad
	GLog->Logf(L"URedirection::GetReferencers()");
	_asm popad

	_asm jmp dwJmp_GetReferencers
}

__declspec (naked) void AllObjects ()
{
	_asm sub esp, 34h					// Fix call stack

	_asm pushad
	GLog->Logf(L"URedirection::AllObjects()");
	_asm popad

	_asm jmp dwJmp_AllObjects
}

FString PointerToString (void* ptr)
{
	return FString::Printf(L"%ls", ptr);
}

void Perform_Check (const TCHAR* Function)
{
	LastFile = *PointerToString(Pointer);

	if (bLogChecks)
	{
		GLog->Logf(L"%ls", Function);
		GLog->Logf(L"SecType : %i", SecType);
		GLog->Logf(L"Param1  : %ls", Param1);
		GLog->Logf(L"Param2  : %ls", Param2);
		GLog->Logf(L" ");
	}

	URedirection_Package* Package = PackageList;

	while (Package)
	{
		if (appStricmp(*PointerToString(Pointer), *Package->Filename) == 0)
		{
			if (Package->Action == 1)
			{
				if (bLogChecks)
					GLog->Logf(L" -> Hiding Package!");

				Param1 = L"HIDE-FILE.u";
			}

			if (Package->Action == 2)
			{
				if (bLogChecks)
					GLog->Logf(L" -> Faking Package!");

				Param1 = Param1;
			}

			if (Package->Action == 3)
			{
				if (bLogChecks)
					GLog->Logf(L" -> Redirecting Package!");
			
				Param1 = Package->Redirect;
			}

			GLog->Logf(L" ");

			return;
		}

		Package = Package->Next;
	}
}

__declspec (naked) void LocalPerform_Init ()
{
	_asm add esp, 4h					// Fix call stack

	_asm mov eax, [ebp-6Ch]
	_asm mov SecType, eax
	_asm mov eax, [ebp-40h]
	_asm mov Param1, eax
	_asm mov Pointer, eax
	_asm mov eax, [ebp-68h]
	_asm mov Param2, eax

	_asm pushad
	Perform_Check(L"********** LocalPerform **********");
	_asm popad

	_asm mov eax, SecType
	_asm mov [ebp-6Ch], eax
	_asm mov eax, Param1
	_asm mov [ebp-40h], eax
	_asm mov eax, Param2
	_asm mov [ebp-68h], eax

	_asm jmp dwJmp_LP_Init
}

__declspec (naked) void LocalPerform_ServerJoin ()
{
	_asm call dwString					// Fix call stack

	// Fake serverjoin results

	_asm jmp dwJmp_LP_ServerJoin
}

__declspec (naked) void LocalPerform_QuickMD5 ()
{
	_asm mov edi, eax					// Fix call stack

	// Fake QuickMD5 results

	_asm jmp dwJmp_LP_QuickMD5
}

void FullMD5_Check ()
{
	URedirection_Package* Package = PackageList;

	while (Package)
	{
		if (Package->Filename == LastFile)
		{
			if (Package->Action == 2)
			{
				Result = Package->FullMD5;

				return;
			}
		}

		Package = Package->Next;
	}
}

__declspec (naked) void LocalPerform_FullMD5 ()
{
	_asm mov edi, [ebp-14h]				// Fix call stack

	_asm mov eax, [ebp-28h]
	_asm mov Result, eax

	_asm pushad
	FullMD5_Check();
	_asm popad

	_asm mov eax, Result
	_asm mov [ebp-28h], eax

	_asm jmp dwJmp_LP_FullMD5
}

__declspec (naked) void LocalPerform_PackageList ()
{
	_asm call dwGetName					// Fix call stack

	// Fake PackageList results

	_asm jmp dwJmp_LP_PackageList
}

__declspec (naked) void NativePerform_Init ()
{
	_asm add esp, 4h					// Fix call stack

	_asm mov eax, [ebp-18h]
	_asm mov SecType, eax
	_asm mov eax, [ebp-3Ch]
	_asm mov Param1, eax
	_asm mov Pointer, eax
	_asm mov eax, [ebp-48h]
	_asm mov Param2, eax

	_asm pushad
	Perform_Check(L"********** NativePerform *********");
	_asm popad

	_asm mov eax, SecType
	_asm mov [ebp-18h], eax
	_asm mov eax, Param1
	_asm mov [ebp-3Ch], eax
	_asm mov eax, Param2
	_asm mov [ebp-48h], eax

	_asm jmp dwJmp_NP_Init
}

LONG WINAPI ExceptionHandler (PEXCEPTION_POINTERS ExceptionInfo)
{
	if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_PRIVILEDGED_INSTRUCTION)
	{
		DWORD dwAddress		= (DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress;
		DWORD dwContinue	= (DWORD)0x0;

		if (dwAddress == dwProcessEvent)
			dwContinue = (DWORD)ProcessEvent;

		if (dwAddress == dwGetReferencers)
			dwContinue = (DWORD)GetReferencers;

		if (dwAddress == dwAllObjects)
			dwContinue = (DWORD)AllObjects;
					
		if (dwAddress == dwLP_Init)
			dwContinue = (DWORD)LocalPerform_Init;

		if (dwAddress == dwLP_ServerJoin)
			dwContinue = (DWORD)LocalPerform_ServerJoin;

		if (dwAddress == dwLP_QuickMD5)
			dwContinue = (DWORD)LocalPerform_QuickMD5;

		if (dwAddress == dwLP_FullMD5)
			dwContinue = (DWORD)LocalPerform_FullMD5;

		if (dwAddress == dwLP_PackageList)
			dwContinue = (DWORD)LocalPerform_PackageList;

		if (dwAddress == dwNP_Init)
			dwContinue = (DWORD)NativePerform_Init;

		if (dwContinue != (DWORD)0x0)
		{
			ExceptionInfo->ContextRecord->Eip = dwContinue;

			return EXCEPTION_CONTINUE_EXECUTION;
		}
	}

	return EXCEPTION_CONTINUE_SEARCH;
}

void HookFunctions ()
{
	if (AddVectoredExceptionHandler(&ExceptionHandler))
	{
		HMODULE hCore = GetModuleHandleA("Core.dll");

		if (hCore != NULL)
		{
			dwFString_0				= ((DWORD)hCore + 0x10BD0);
			dwFString_4				= ((DWORD)hCore + 0x10D30);
			dwString				= ((DWORD)hCore + 0x024D0);
			dwPrintf				= ((DWORD)hCore + 0x3C9C0);
			dwGetName				= ((DWORD)hCore + 0x0CC10);
			dwProcessEvent			= ((DWORD)hCore + 0x2FFC0);
			dwGetReferencers		= ((DWORD)hCore + 0x49F1B);
			dwAllObjects			= ((DWORD)hCore + 0x31C00);

			dwJmp_ProcessEvent		= HookFunction(dwProcessEvent, 1);
			dwJmp_GetReferencers	= HookFunction(dwGetReferencers, 3);
			dwJmp_AllObjects		= HookFunction(dwAllObjects, 3);
		}

		HMODULE hEngine = GetModuleHandleA("Engine.dll");

		if (hEngine != NULL)
		{
			dwLP_Init				= ((DWORD)hEngine + 0x1D2100);
			dwLP_ServerJoin			= ((DWORD)hEngine + 0x124BA8);
			dwLP_QuickMD5			= ((DWORD)hEngine + 0x1D220B);
			dwLP_FullMD5			= ((DWORD)hEngine + 0x1D24ED);
			dwLP_PackageList		= ((DWORD)hEngine + 0x1D2631);
			dwNP_Init				= ((DWORD)hEngine + 0x1D1957);

			dwJmp_LP_Init			= HookFunction(dwLP_Init, 3);
			dwJmp_LP_ServerJoin		= HookFunction(dwLP_ServerJoin, 6);
			dwJmp_LP_QuickMD5		= HookFunction(dwLP_QuickMD5, 2);
			dwJmp_LP_FullMD5		= HookFunction(dwLP_FullMD5, 3);
			dwJmp_LP_PackageList	= HookFunction(dwLP_PackageList, 6);
			dwJmp_NP_Init			= HookFunction(dwNP_Init, 3);
		}
	}
}
BOOL APIENTRY DllMain (HMODULE hDll, DWORD dwReason, LPVOID lpReserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hDll);
		
		// Loaded stuff from .ini

		URedirection_Package* Package = new URedirection_Package();

		if (Package)
		{
			// Used for testing ...
			Package->Filename	= L"../System/Core.u";
			Package->Redirect	= L"../System/UWeb.u";
			Package->Action		= 3;
			Package->QuickMD5	= L"6be19afbaecd190118377763a517cc86";
			Package->FullMD5	= L"7c56df7e3b1d3ba9ab22bc2409838c5e";
			Package->GUID		= L"1A7E493D4127EB5494CCAFA3110DF855";
			
			if (PackageList)
				Package->Next	= PackageList;
			else
				PackageList		= Package;
		}

		HookFunctions();

	}

	return 1;
}