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

#define LDE_X86 0
#define	DLL_NAME		"inject_dbg_safe.dll"

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

DWORD		check_next_bytes(BYTE *p)
{
	while (*p == 0xCC)
		p++;
	if (*p == 0x90)
	{
		// Alignement ?
		return 0;
	}
	return 1;
}

void		setup_ret_stolen_bytes(void)
{
	DWORD	OldProtect;
	BYTE	*addr = (BYTE*)0x6673E0FA;

	/*	.text:6673E0F6                 lea     ecx, [esp+34h+var_30]
		.text:6673E0FA                 call    sub_6673E110
		.text:6673E0FF                 mov     ax, 1
		
		||
		\/

		6673E0FA    83C4 7C                 ADD ESP,7C
		6673E0FD    C3                      RET */
	VirtualProtect((LPVOID)0x6673E0FA, 4, PAGE_EXECUTE_READWRITE, &OldProtect);
	addr[0] = 0x83;
	addr[1] = 0xC4;
	addr[2] = 0x7C;
	addr[3] = 0xC3;
	VirtualProtect((LPVOID)0x6673E0FA, 4, OldProtect, &OldProtect);
}

void		fix_stolen_bytes(void)
{
	DWORD	addr_stolen[18] = {0x00423000, 0x004424AF, 0x00443C0A, 0x00445BB4,
							0x00445DE1, 0x00445DE6, 0x00445E34, 0x00445E3B,
							0x0044606E, 0x00446075, 0x004464E1, 0x0044FC70,
							0x0044FD20, 0x00450303, 0x00450332, 0x00450734,
							0x00450739,0x00451B21};
	DWORD	i;
	DWORD	addr;

	setup_ret_stolen_bytes();

	for (i = 0; i < 18; i++)
	{
		addr = addr_stolen[i];
		__asm
		{
				pushad
				jmp		end
			go:
				push	addr
				ret

			end:
				call	go
				popad
		}
	}

}

void		fix_nanomites(void)
{
	FILE	*fp = NULL;
	IMAGE_DOS_HEADER *idh = NULL;
	IMAGE_NT_HEADERS *inh = NULL;
	IMAGE_SECTION_HEADER *ish_txt = NULL;
	DWORD imagebase;
	DWORD imageend;
	DWORD i;
	BYTE *ptr;
	HANDLE	hThread;
	DWORD	ThreadId;
	char	buf_error[100];

	imagebase = (DWORD)GetModuleHandle(NULL);
	idh = (IMAGE_DOS_HEADER *)imagebase;
	inh = (IMAGE_NT_HEADERS *)((BYTE*)imagebase + idh->e_lfanew);
	ish_txt = (IMAGE_SECTION_HEADER*)((BYTE*)inh + sizeof (IMAGE_NT_HEADERS));

	for (i = 0; i < ish_txt->Misc.VirtualSize; i++)
	{
		ptr = (BYTE*)(imagebase + ish_txt->VirtualAddress + i);
		//addr_to_jump = (DWORD)ptr;
		if (*ptr == 0xCC && *(ptr + 1) == 0xCC)
		{
			if (!check_next_bytes(ptr))
			{
				continue;
			}
			/* Maybe Nanomites */
			hThread = CreateThread(NULL, 100, (LPTHREAD_START_ROUTINE)(ptr)/*(imagebase + ish_txt->VirtualAddress + i)*/, NULL, STACK_SIZE_PARAM_IS_A_RESERVATION, &ThreadId);
			if (hThread == NULL)
			{
				sprintf(buf_error, "CreateThread failed : %X", GetLastError());
				MessageBoxA(NULL, buf_error, "failed", 0);
				exit(EXIT_FAILURE);
			}
			
			fp = fopen("debug_msg_nanomites.txt", "a");
			fprintf(fp, "[+/-] Test Nanomites at Addr 0x%X : (TID = %X)\n", (ptr)/*(imagebase + ish_txt->VirtualAddress + i)*/, ThreadId);
			fclose(fp);
			WaitForSingleObject(hThread, INFINITE);
			CloseHandle(hThread);
		}
	}
}

void		fix_code_call(void)
{
	DWORD	OldProtect;
	BYTE	*addr = (BYTE*)0x6678D649;

	/*	.txt:6678D644 call    sub_6678D1DF				<< COMPUTE ADDR API
		.txt:6678D649 pop     ecx
		.txt:6678D64A pop     ecx
		
		||
		\/

		6678D649    81 C4 84 00 00 00   ADD ESP,84
		6678D64F    C3					RET */

	VirtualProtect((LPVOID)0x6678D649, 8, PAGE_EXECUTE_READWRITE, &OldProtect);
	addr[0] = 0x81;
	addr[1] = 0xC4;
	addr[2] = 0x84;
	addr[3] = 0x00;
	addr[4] = 0x00;
	addr[5] = 0x00;
	addr[6] = 0xC3;
	addr[7] = 0x90;
	VirtualProtect((LPVOID)0x6678D649, 8, OldProtect, &OldProtect);

	/*	.txt:6678D3CC                 push    0FFFFFFFFh      ; dwMilliseconds
		.txt:6678D3CE                 push    dword_667EF2F8  ; hHandle
		.txt:6678D3D4                 call    ds:WaitForSingleObject			*/

	VirtualProtect((LPVOID)0x6678D3CC, 14, PAGE_EXECUTE_READWRITE, &OldProtect);
	memset((LPVOID)0x6678D3CC, 0x90, 14);
	VirtualProtect((LPVOID)0x6678D3CC, 14, OldProtect, &OldProtect);
}

DWORD		call_resolve(DWORD addr, DWORD is_jmp)
{
	DWORD	solve_addr;

	__asm
	{
			pushad
			jmp		end
		go:
			mov		eax, is_jmp
			test	eax, eax
			jz		dont_set_jmp
			push	0xDEADBEEF

		dont_set_jmp:
			push	addr
			ret

		end:
			call	go
			mov		[esp + 0x1C], eax
			popad
			mov		solve_addr, eax
	}
}

void		fix_call(void)
{
	FILE	*fp = NULL;
	IMAGE_DOS_HEADER *idh = NULL;
	IMAGE_NT_HEADERS *inh = NULL;
	IMAGE_SECTION_HEADER *ish_txt = NULL;
	IMAGE_SECTION_HEADER *ish_rdata = NULL;
	DWORD imagebase;
	DWORD imageend;
	DWORD i;
	BYTE *ptr;
	DWORD val;
	BYTE *p_val;
	DWORD	addr;
	DWORD is_jmp;
	DWORD solve_addr;
	DWORD	OldProtect;
	struct api_s *ap = NULL;

	fix_code_call();
	fp = fopen("debug_msg.txt", "w");
	if (!fp)
		MessageBoxA(NULL, "fopen failed :(", "failed", 0);
	imagebase = (DWORD)GetModuleHandle(NULL);
	idh = (IMAGE_DOS_HEADER *)imagebase;
	inh = (IMAGE_NT_HEADERS *)((BYTE*)imagebase + idh->e_lfanew);
	ish_txt = (IMAGE_SECTION_HEADER*)((BYTE*)inh + sizeof (IMAGE_NT_HEADERS));
	ish_rdata = (IMAGE_SECTION_HEADER*)((BYTE*)inh + sizeof (IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER));

	imageend = imagebase + inh->OptionalHeader.SizeOfImage;
	fprintf(fp, "Image Base : %08X\nImage End : %08X\n", imagebase, imageend);
	fprintf(fp, "Section Name TXT %s\n", ish_txt->Name);
	fprintf(fp, "Section Name TXT %s\n", ish_rdata->Name);
	fclose(fp);
	for (i = 0; i < ish_txt->Misc.VirtualSize; i++)
	{
		ptr = (BYTE*)(imagebase + ish_txt->VirtualAddress + i);
		/* CALL DWORD PTR OR JMP DWORD PTR */
		if ((*ptr == 0xFF && *(ptr + 1) == 0x15) || (*ptr == 0xFF && *(ptr + 1) == 0x25))
		{
			val = *(ptr + 5) << 0x18 | *(ptr + 4) << 0x10 | *(ptr + 3) << 0x8  | *(ptr + 2);
			if (val >= (ish_rdata->VirtualAddress + imagebase) && val <= (ish_rdata->VirtualAddress + imagebase + ish_rdata->Misc.VirtualSize))
			{
				p_val = (BYTE*)(*(DWORD*)val);
				/*	02500F9F    68 9412EABF     PUSH BFEA1294
					02500FA4    9C              PUSHFD
					02500FA5    60              PUSHAD */
				if (*p_val == 0x68 && *(p_val + 5) == 0x9C && *(p_val + 0x6) == 0x60)
				{
					fp = fopen("debug_msg.txt", "a");
					is_jmp = 0;
					if (*ptr == 0xFF && *(ptr + 1) == 0x15)
						fprintf(fp, "Find CALL DWORD PTR[%X] at Addr %X\n", val, (imagebase + ish_txt->VirtualAddress + i));
					else
					{
						fprintf(fp, "Find JMP DWORD PTR[%X] at Addr %X\n", val, (imagebase + ish_txt->VirtualAddress + i));
						is_jmp = 1;
					}
					fclose(fp);
					addr = (imagebase + ish_txt->VirtualAddress + i);

					solve_addr = call_resolve(addr, is_jmp);

					fp = fopen("debug_msg.txt", "a");
					fprintf(fp, "[+] Solved Addr = %X\n", solve_addr);
					fclose(fp);

					ap = add_api(ap, solve_addr, val, (DWORD)(ptr + 2), 0);
				}
			}
		}
		/* JMP Stxt774 */
		else if (*ptr == 0xE9)
		{
			val = *(ptr + 4) << 0x18 | *(ptr + 3) << 0x10 | *(ptr + 2) << 0x8  | *(ptr + 1);
			/* compute dest jmp */
			val = (DWORD)ptr + val + 5;
			/* fix those addr, it's ugly */
			if (val >= 0x01864000 && val <= 0x1867000)
			{
				fp = fopen("debug_msg.txt", "a");
				fprintf(fp, "Find JMP Stxt774(%X) at Addr %X\n", val, ptr);
				fclose(fp);
				addr = (imagebase + ish_txt->VirtualAddress + i);
				solve_addr = call_resolve(addr, 0);
				fp = fopen("debug_msg.txt", "a");
				fprintf(fp, "[+] Solved Addr = %X\n", solve_addr);
				fclose(fp);
				ap = add_api(ap, solve_addr, val, addr, 1);
			}
		}
	}
	fp = fopen("debug_msg.txt", "a");
	print_api(fp, ap);
	reorder_api_rdata(ap);
	fprintf(fp, "AFTER REORDER !!!\n");
	print_api(fp, ap);
	fclose(fp);
	fix_api_rdata(ap);
}

BOOL (__stdcall *Resume_GetVersionExA)(LPOSVERSIONINFO lpVersionInfo) = NULL;

BOOL __stdcall Hook_GetVersionExA(LPOSVERSIONINFO lpVersionInfo)
{
	DWORD	return_addr;

	__asm
	{
		mov eax, [ebp + 4]
		mov return_addr, eax
	}
	/*	.text:0051DD6C                 call    ds:dword_5331F0
		.text:0051DD72                 mov     ecx, [esi+10h] */
	if (return_addr == 0x0051DD72)
	{
		fix_nanomites();
		MessageBoxA(NULL, "Fix Nanomites finish !", "Fuck Yeah !", 0);
		fix_call();
		MessageBoxA(NULL, "Fix Call finish !", "Fuck Yeah !", 0);
		fix_stolen_bytes();
		MessageBoxA(NULL, "Fix Stolen Bytes finish !", "Fuck Yeah !", 0);
		__asm jmp $
	}
	return Resume_GetVersionExA(lpVersionInfo);
}

BOOL (__stdcall *Resume_CreateProcessA)(LPCSTR lpApplicationName,
										LPSTR lpCommandLine,
										LPSECURITY_ATTRIBUTES lpProcessAttributes,
										LPSECURITY_ATTRIBUTES lpThreadAttributes,
										BOOL bInheritHandles,
										DWORD dwCreationFlags,
										LPVOID lpEnvironment,
										LPCSTR lpCurrentDirectory,
										LPSTARTUPINFOA lpStartupInfo,
										LPPROCESS_INFORMATION lpProcessInformation) = NULL;

BOOL __stdcall Hook_CreateProcessA(LPCSTR lpApplicationName,
										LPSTR lpCommandLine,
										LPSECURITY_ATTRIBUTES lpProcessAttributes,
										LPSECURITY_ATTRIBUTES lpThreadAttributes,
										BOOL bInheritHandles,
										DWORD dwCreationFlags,
										LPVOID lpEnvironment,
										LPCSTR lpCurrentDirectory,
										LPSTARTUPINFOA lpStartupInfo,
										LPPROCESS_INFORMATION lpProcessInformation)
{
	BOOL result;
	DWORD	Addr;
	HANDLE	hThread;
	HMODULE	hKernel32;

	MessageBoxA(NULL, "CREATEPROCESS A CALLED", "Error", 0);

	hKernel32 = GetModuleHandleA("kernel32.dll");
	/* Change Creation flag to CREATE_SUSPENDED */
	dwCreationFlags = CREATE_SUSPENDED;
	/* Call real CreateProcess function */
	result = Resume_CreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes, 
					lpThreadAttributes, bInheritHandles, dwCreationFlags,
					lpEnvironment, lpCurrentDirectory, lpStartupInfo, 
					lpProcessInformation);
	Addr = (DWORD)VirtualAllocEx(lpProcessInformation->hProcess, 0, strlen(DLL_NAME) + 1, 
					MEM_COMMIT, PAGE_READWRITE);
	if (Addr == NULL)
	{
		MessageBoxA(NULL, "VirtualAllocEx failed()", "Error", 0);
		TerminateProcess(lpProcessInformation->hProcess, 42);
		exit(EXIT_FAILURE);
	}
	WriteProcessMemory(lpProcessInformation->hProcess, (LPVOID)Addr, (void*)DLL_NAME, strlen(DLL_NAME) + 1, NULL);
	hThread = CreateRemoteThread(lpProcessInformation->hProcess, NULL, 0,
					(LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryA" ), 
					(LPVOID)Addr, 0, NULL);
	WaitForSingleObject(hThread, INFINITE);
	ResumeThread(lpProcessInformation->hThread);
	CloseHandle(hThread);
	return (result);
}

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_hook_create_processa(void)
{
	/* Alloc enough place for CreateProcessA Hook */
	Resume_CreateProcessA = (BOOL(__stdcall *)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, 
							LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, 
							LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION))
							VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	if (!Resume_CreateProcessA)
	{
		MessageBoxA(NULL, "VirtualAllocEx failed()", "Error", 0);
		return;
	}
	memset(Resume_CreateProcessA, 0x90, 0x1000);
	setup_hook("kernel32.dll", "CreateProcessA", &Hook_CreateProcessA, Resume_CreateProcessA, 0);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
	DisableThreadLibraryCalls(GetModuleHandleA("inject_safe.dll"));

	Resume_GetVersionExA = (BOOL(__stdcall *)(LPOSVERSIONINFO))VirtualAlloc(0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memset(Resume_GetVersionExA, 0x90, 0x1000);

	setup_hook("kernel32.dll", "GetVersionExA", &Hook_GetVersionExA, Resume_GetVersionExA, 0);

	setup_hook_create_processa();

	return (1);
}