#include <windows.h>
#include <detours.h>
#include <math.h>
#include <stdio.h>

#include "Core.h"
#include "Engine.h"
#include "UnLinker.h" 

#define EXCEPTION_PRIVILEDGED_INSTRUCTION (DWORD)0xc0000096

enum E_FILEACTION {
	FILE_HIDE,
	FILE_FAKE,
	FILE_REDIRECT
};

struct URedirection_Plugin {
	class UObject* Object;
	FString Filename;
	URedirection_Plugin* Next;
};

struct URedirection_Package {
	FString Filename;
	FString Redirect;
	E_FILEACTION Action;
	FString QuickMD5;
	FString FullMD5;
	FString GUID;
	FString Linker;
	URedirection_Package* Next;
};

URedirection_Plugin* PluginList		= 0;
URedirection_Package* PackageList	= 0;

UBOOL bHidePlugins					= 1;
UBOOL bLogPlugins					= 1;
UBOOL bLogChecks					= 1;

// Core 3369 hook related
DWORD dwAddZeroed					= 0;	// 10101ED0									?AddZeroed@FArray@@QAEHHH@Z
DWORD dwQuickMD5					= 0;	// 101345F0									?QuickMD5@ULinker@@QAE?AVFString@@XZ
DWORD dwDFString					= 0;	// 1010C4F0									??DFString@@QBEPBGXZ
DWORD dwString						= 0;	// 101024D0									?String@FGuid@@QBEPAGXZ
DWORD dwGetName						= 0;	// 1010CC10									?GetName@UObject@@QBEPBGXZ

DWORD dwLinkers						= 0;	// 1014F232  8B1481                    		mov	edx,[ecx+eax*4]
DWORD dwProcessEvent				= 0;	// 1012FFC0									?ProcessEvent@UObject@@UAEXPAVUFunction@@PAX1@Z
DWORD dwGetReferencers				= 0;	// 10149F1B  83C408                    		add	esp,00000008h
DWORD dwAllObjects					= 0;	// 10131C00									?execAllObjects@UObject@@QAEXAAUFFrame@@QAX@Z
DWORD dwGetDirectoryFiles			= 0;	// 1015FF57  8B01                      		mov	eax,[ecx]

DWORD dwJmp_Linkers					= 0;	// 1014F235  52                        		push	edx
DWORD dwJmp_Inc_Linkers				= 0;	// 1014F313  40                        		inc	eax
DWORD dwJmp_Log_Linkers				= 0;	// 1014F307  51                        		push	ecx
DWORD dwJmp_ProcessEvent			= 0;	// 1012FFC1  8BEC                      		mov	ebp,esp
DWORD dwJmp_GetReferencers			= 0;	// 101488EC  8B1CBA                    		mov	ebx,[edx+edi*4]
DWORD dwJmp_AllObjects				= 0;	// 10131CF1  8B0CAA                    		mov	ecx,[edx+ebp*4]
DWORD dwJmp_GetDirectoryFiles		= 0;	// 1015FF59  83EC0C                    		sub	esp,0000000Ch
DWORD dwJmp_Inc_Files				= 0;	// 1015FF7A  46                        		inc	esi

// Engine 3369 hook related
DWORD dwGetCDKeyHash				= 0;	// 103F5950									?GetCDKeyHash@@YA?AVFString@@XZ:
DWORD dwLP_Init						= 0;	// 104D2100  83C404                    		add	esp,00000004h
DWORD dwLP_QuickMD5					= 0;	// 104D21E8  85C0                      		test	eax,eax
DWORD dwLP_FullMD5					= 0;	// 104D24ED  8B7DEC                    		mov	edi,[ebp-14h]
DWORD dwLP_PackageList				= 0;	// 104D25F1  FF15F8616110              		call	[Core.dll!?AddZeroed@FArray@@QAEHHH@Z]
DWORD dwNP_Init						= 0;	// 104D1957  83C404                    		add	esp,00000004h
DWORD dwNP_ServerCallback			= 0;
DWORD dwPawnConstructor				= 0;	// 10367AF5  51                        		push	ecx
DWORD dwPawnDestructor				= 0;	// 10367A55  51                        		push	ecx

DWORD dwJmp_GetCDKeyHash			= 0;	// 103F5952  6803945F10                		push	L105F9403
DWORD dwJmp_LP_Init					= 0;	// 104D2103  8B4594                    		mov	eax,[ebp-6Ch]
DWORD dwJmp_LP_QuickMD5				= 0;	// 104D220D  FF15486C6110              		call	[Core.dll!??DFString@@QBEPBGXZ]
DWORD dwJmp_LP_FullMD5				= 0;	// 104D24F0  6A01                      		push	00000001h
DWORD dwJmp_LP_PackageList			= 0;	// 104D2637  8B4DE8                    		mov	ecx,[ebp-18h]
DWORD dwJmp_LP_PackageList_Inc		= 0;	// 104D268C  8B45E4                    		mov	eax,[ebp-1Ch]
DWORD dwJmp_LP_PackageList_Printf	= 0;	// 104D263E  8D95D8FEFFFF              		lea	edx,[ebp-00000128h]
DWORD dwJmp_NP_Init					= 0;	// 104D195A  8B45E8                    		mov	eax,[ebp-18h]
DWORD dwJmp_NP_ServerCallback		= 0;
DWORD dwJmp_PawnConstructor			= 0;
DWORD dwJmp_PawnDestructor			= 0;

// Linker hooked function parameters
class ULinkerLoad* Linker;

bool bHideLinker					= false;
bool bFakeLinker					= false;

FString StrLinker0					= L"%ls";
FString StrLinker1					= L"THIS_IS_A_FAKE_LINKER";

// MD5 hooked function parameters
int SecType;
FString Param1;
FString Param2;
void* Pointer;
FString Str_GUID;
FString Str_QuickMD5;
FString Str_FullMD5;
FString LastFile					= L"UNKNOWN_FILE";
FString Data;

// File hooked function parameters
bool bHideFile						= false;

// Packagelist hooked function parameters
bool bHidePackage					= false;
bool bFakePackage					= false;

// CDKeyHash hooked function parameters
FString CDKeyHash					= L"";

// Pawn Constructor/Destructor parameters
APawn *pTarget;

bool AddVectoredExceptionHandler (void* pHandler)
{
	void* AddVectoredExceptionHandler = (void*)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "AddVectoredExceptionHandler");

	if (AddVectoredExceptionHandler)
	{
		_asm
		{
			push pHandler
			push 1
			call AddVectoredExceptionHandler
		}
	}

	return true;
}

DWORD HookFunction (DWORD dwAddress, int iSkip)
{
	if (iSkip < 1)
		return 0;

	DWORD dwProtect = PAGE_EXECUTE_READWRITE;

	VirtualProtect((void*)dwAddress, 1, dwProtect, &dwProtect);
	((BYTE*)dwAddress)[0] = 0xF4; // HLT Opcode - PRIV_INSTRUCTION
	VirtualProtect((void*)dwAddress, 1, dwProtect, &dwProtect);

	return (DWORD)(dwAddress + iSkip);
}

FString StripFilePath (FString Str)
{
	if (Str.InStr(L"../") != -1)
	{
		Str = Str.Mid(3);
		Str = Str.Mid(Str.InStr(L"/") + 1);
	}

	if (Str.InStr(L"..\\") != -1)
	{
		Str = Str.Mid(3);
		Str = Str.Mid(Str.InStr(L"\\") + 1);
	}

	return Str;
}

FString StripFileExt (FString Str)
{
	if (Str.InStr(L".") != -1)
	{
		Str = Str.Left(Str.InStr(L"."));
	}

	return Str;
}

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

#define LogPath "URedirection.log"

void Log (const char *fmt, ...)
{
	va_list va_alist;
	static char logbuf[1024];

	if (fmt==NULL) return;
	
	FILE *fp;
	
	va_start (va_alist, fmt);
	_vsnprintf(logbuf, sizeof(logbuf), fmt, va_alist);
	va_end (va_alist);
	
	if ((fp=fopen (LogPath, "a+"))!=NULL)
	{
		fprintf(fp, "%s\n", logbuf);
		fclose (fp);
	}
}