#include <stdio.h>
#include <Windows.h>

#define LDE_X86 0

#ifdef __cplusplus
extern "C"
#endif
int __stdcall LDE(void* address , DWORD type);

FILE	*fp;
DWORD	first_call = 0;
LPDEBUG_EVENT	dbg_event;
EXCEPTION_DEBUG_INFO except_di;
EXCEPTION_RECORD except_r;
HANDLE HThread;

void setup_AfterWaitForDebugEvent(void);
void setup_Hook_WriteProcessMemory(void);
void setup_Hook_SetThreadContext(void);
void setup_Hook_GetThreadContext(void);
void setup_Hook_FailedNanomites(void);

DWORD (__stdcall *Get_hThread)(DWORD) = (DWORD(__stdcall *)(DWORD))0x6678E5E8;

BOOL (__stdcall *Resume_GetThreadContext)(HANDLE hThread, CONTEXT *lpContext) = NULL;

BOOL __stdcall Hook_GetThreadContext(HANDLE hThread, CONTEXT *lpContext)
{
		DWORD	return_addr;

	__asm
	{
		mov eax, [ebp + 4]
		mov return_addr, eax
	}
	fp = fopen("debug_msg_dbg.txt", "a");
	if (!fp)
		MessageBoxA(NULL, "fopen failed :(", "failed", 0);
	fprintf(fp, "[+] GetThreadContext(0x%X, 0x%X); return_addr = %X\n", hThread, lpContext, return_addr);
	fprintf(fp, "lpContext->EIP = %X\n", lpContext->Eip);
	fclose(fp);
	return (Resume_GetThreadContext(hThread, lpContext));
}

DWORD (__stdcall *Resume_FailedNanomites)(void) = NULL;

DWORD __declspec ( naked ) Hook_FailedNanomites(void)
{
	__asm
	{
		pushad
/* 
.text:66733C0A loc_66733C0A:                           ; CODE XREF: Call_SetThreadContext+Aj
.text:66733C0A                 mov     eax, [esi+4]
.text:66733C0D                 mov     ecx, [esi+8]
.text:66733C10                 push    dword ptr [eax+8]
.text:66733C13                 call    Get_htread ; 0x6678E5E8
*/
		mov		eax, [esi + 4]
		mov		ecx, [esi + 8]
		push	dword ptr [eax + 8]
		call	Get_hThread
		mov		HThread, eax
	}
	TerminateThread(HThread, 0);
	__asm
	{
		popad
		jmp		Resume_FailedNanomites
	}
}

void hexdump(BYTE *buf, int size, FILE *fp)
{
	int i;

	for (i = 0; i < size; i++)
	{
		fprintf(fp, "%02X ", buf[i]);
	}
	fprintf(fp, "\n");
}

BOOL (__stdcall *Resume_SetThreadContext)(HANDLE hThread, CONTEXT *lpContext) = NULL;

BOOL __stdcall Hook_SetThreadContext(HANDLE hThread, CONTEXT *lpContext)
{
	DWORD	return_addr;

	__asm
	{
		mov eax, [ebp + 4]
		mov return_addr, eax
	}
	fp = fopen("debug_msg_dbg.txt", "a");
	if (!fp)
		MessageBoxA(NULL, "fopen failed :(", "failed", 0);
	fprintf(fp, "[+] SetThreadContext(0x%X, 0x%X); return_addr = %X\n", hThread, lpContext, return_addr);
	fprintf(fp, "lpContext->EIP = %X\n", lpContext->Eip);
	fclose(fp);
	TerminateThread(hThread, 0);
	return 1;
	return (Resume_SetThreadContext(hThread, lpContext));
}

BOOL (__stdcall *Resume_WriteProcessMemory)(HANDLE hProcess,
											LPVOID lpBaseAddress,
											LPCVOID lpBuffer,
											SIZE_T nSize,
											SIZE_T * lpNumberOfBytesWritten) = NULL;

BOOL __stdcall Hook_WriteProcessMemory(HANDLE hProcess,
											LPVOID lpBaseAddress,
											LPCVOID lpBuffer,
											SIZE_T nSize,
											SIZE_T *lpNumberOfBytesWritten)
{
	DWORD	return_addr;

	__asm
	{
		mov eax, [ebp + 4]
		mov return_addr, eax
	}
	fp = fopen("debug_msg_dbg.txt", "a");
	if (!fp)
		MessageBoxA(NULL, "fopen failed :(", "failed", 0);
	fprintf(fp, "[+] WriteProcessMemory(0x%X, 0x%X, 0x%X, 0x%X, 0x%X); return_addr = %X\n", hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten, return_addr);
	hexdump((BYTE*)lpBuffer, nSize, fp);
	fclose(fp);
	return (Resume_WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten));
}

DWORD (__stdcall *Resume_BeforeCall0x12121212)(void) = NULL;

DWORD __declspec ( naked ) Hook_BeforeCall0x12121212(void)
{
	__asm
	{
		pushad
	}
	setup_AfterWaitForDebugEvent();
	__asm
	{
		popad
		jmp Resume_BeforeCall0x12121212
	}
}

DWORD (__stdcall *Resume_AfterWaitForDebugEvent)(void) = NULL;

DWORD __declspec ( naked ) Hook_AfterWaitForDebugEvent(void)
{
	__asm
	{
		pushad
		mov dbg_event, eax
	}
	if (!first_call)
	{
		setup_Hook_WriteProcessMemory();
		setup_Hook_GetThreadContext();
		setup_Hook_SetThreadContext();
		setup_Hook_FailedNanomites();
		fp = fopen("debug_msg_dbg.txt", "w");
		first_call = 1;
		if (!fp)
			MessageBoxA(NULL, "fopen failed :(", "failed", 0);
	}
	else
	{
		fp = fopen("debug_msg_dbg.txt", "a");
		if (!fp)
			MessageBoxA(NULL, "fopen failed :(", "failed", 0);
	}
	fprintf(fp, "---\n");
	fprintf(fp, "Process id : %X\n", dbg_event->dwProcessId);
	fprintf(fp, "EventCode : %X\n", dbg_event->dwDebugEventCode);
	if (dbg_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
	{
		except_di = dbg_event->u.Exception;
		except_r = except_di.ExceptionRecord;
		fprintf(fp, "Exception Code : %X\n", except_r.ExceptionCode);
		fprintf(fp, "Exception Addr : %X\n", except_r.ExceptionAddress);
	}
	else if (dbg_event->dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
	{
		
	}
	fprintf(fp, "---\n");
	fclose(fp);
	__asm
	{
		popad
		jmp Resume_AfterWaitForDebugEvent
	}
}

void	setup_hook(char *module, char *name_export, void *Hook_func, void *trampo, DWORD addr)
{
	DWORD	OldProtect;
	DWORD	len;
	FARPROC	Proc;

	if (addr != 0)
	{
		Proc = (FARPROC)addr;
	}
	else
	{
		Proc = GetProcAddress(GetModuleHandleA(module), name_export);
		if (!Proc)
			MessageBoxA(NULL, name_export, module, 0);
	}
	len = 0;
	while (len < 5)
		len += LDE((BYTE*)Proc + len , LDE_X86);
	memcpy(trampo, Proc, len);
	*(BYTE *)((BYTE*)trampo + len) = 0xE9;
	*(DWORD *)((BYTE*)trampo + len + 1) = (BYTE*)Proc - (BYTE*)trampo - 5;
	VirtualProtect(Proc, len, PAGE_EXECUTE_READWRITE, &OldProtect);
	*(BYTE*)Proc = 0xE9;
	*(DWORD*)((char*)Proc + 1) = (BYTE*)Hook_func - (BYTE*)Proc - 5;
	VirtualProtect(Proc, len, OldProtect, &OldProtect);
}

void setup_AfterWaitForDebugEvent(void)
{
	Resume_AfterWaitForDebugEvent = (DWORD(__stdcall *)(void))VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(Resume_AfterWaitForDebugEvent, 0x90, 0x1000);
	/*  .txt5:6678E46C                 lea     eax, [ebp+var_74]
		.txt5:6678E46F                 push    eax
		.txt5:6678E470				   push    esi */
	setup_hook("CODSP", "CODSP", &Hook_AfterWaitForDebugEvent, Resume_AfterWaitForDebugEvent, 0x6678E46F);
}

void setup_BeforeCall0x12121212(void)
{
	Resume_BeforeCall0x12121212 = (DWORD(__stdcall *)(void))VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(Resume_BeforeCall0x12121212, 0x90, 0x1000);
	/* .text:00401378 push    ecx
	.text:00401379 call    eax
	.text:0040137B pop   */
	setup_hook("CODSP", "CODSP", &Hook_BeforeCall0x12121212, Resume_BeforeCall0x12121212, 0x00401378);
}

void setup_Hook_WriteProcessMemory(void)
{
	DWORD OldProtect;

	Resume_WriteProcessMemory = (BOOL(__stdcall *)(HANDLE,LPVOID,LPCVOID,SIZE_T,PSIZE_T))VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(Resume_WriteProcessMemory, 0x90, 0x1000);
	setup_hook("kernel32.dll", "WriteProcessMemory", &Hook_WriteProcessMemory, Resume_WriteProcessMemory, 0);

	/* patch jnz */
	VirtualProtect((LPVOID)0x6678F566, 6, PAGE_EXECUTE_READWRITE, &OldProtect);
	memset((void*)0x6678F566, 0x90, 6);
	VirtualProtect((LPVOID)0x6678F566, 6, OldProtect, &OldProtect);
}

void setup_Hook_SetThreadContext(void)
{
	Resume_SetThreadContext = (BOOL(__stdcall *)(HANDLE hThread, CONTEXT *lpContext))VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(Resume_SetThreadContext, 0x90, 0x1000);
	setup_hook("kernel32.dll", "SetThreadContext", &Hook_SetThreadContext, Resume_SetThreadContext, 0);
}

void setup_Hook_GetThreadContext(void)
{
	Resume_GetThreadContext = (BOOL(__stdcall *)(HANDLE hThread, CONTEXT *lpContext))VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(Resume_GetThreadContext, 0x90, 0x1000);
	setup_hook("kernel32.dll", "GetThreadContext", &Hook_GetThreadContext, Resume_GetThreadContext, 0);
}

void setup_Hook_FailedNanomites(void)
{
	Resume_FailedNanomites = (DWORD(__stdcall *)(void))VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(Resume_FailedNanomites, 0x90, 0x1000);
	/*  .txt5:66790291                 mov     dword ptr [esi+0Ch], 80010001h
		.txt5:66790298                 jmp     loc_66790339 */
	setup_hook("CODSP", "CODSP", &Hook_FailedNanomites, Resume_FailedNanomites, 0x66790291);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
	DisableThreadLibraryCalls(GetModuleHandleA("inject_dbg_safe.dll"));
	setup_BeforeCall0x12121212();
	return (1);
}