#include <windows.h>

#define FIND_VTABLE 0
#define PATCH_RET 1
#define DO_DIFF 2
#define DO_FINAL 3

#define STEP DO_FINAL

int main(int argc, char **argv) {
	DWORD PID;
	HWND hWnd;
	HANDLE proc;
	DWORD oldProtect;
	unsigned char opBuf[128];
	unsigned char readBuf[128];

	hWnd = FindWindow(NULL, "DestinaRO Client v2.1");
	if( !hWnd ) {
		MessageBox(NULL, "DestinaRO is not running", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	GetWindowThreadProcessId(hWnd, &PID);
	if( !PID ) {
		MessageBox(NULL, "DestinaRO is not running?", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	proc = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, PID);
	if( !proc ) {
		MessageBox(NULL, "Failed to attach to DestinaRO", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

#if STEP == FIND_VTABLE

	if( !VirtualProtectEx(proc, 0x4E805F, 7, PAGE_EXECUTE_READWRITE, &oldProtect) ) {
		MessageBox(NULL, "Failed to attach to DestinaRO [2]", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	// mov ecx, eax (probably not needed anyway)
	opBuf[0] = 0x8B;
	opBuf[1] = 0xC8;
	// mov eax, ds:0
	opBuf[2] = 0xA1;
	opBuf[3] = 0x00;
	opBuf[4] = 0x00;
	opBuf[5] = 0x00;
	opBuf[6] = 0x00;

	if( !WriteProcessMemory(proc, 0x4E805F, opBuf, 7, NULL) ) {
		MessageBox(NULL, "Failed to patch DestinaRO", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	if( !VirtualProtectEx(proc, 0x4E805F, 7, oldProtect, &PID) ) {
		MessageBox(NULL, "Failed to attach to DestinaRO [2]", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

#elif STEP == PATCH_RET
	if( !ReadProcessMemory(proc, 0x6F5BBC + 0x6C, readBuf, 4, NULL) ) {
		MessageBox(NULL, "Failed to read DestinaRO", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	if( !VirtualProtectEx(proc, *(void**)&readBuf[0], 3, PAGE_EXECUTE_READWRITE, &oldProtect) ) {
		MessageBox(NULL, "Failed to attach to DestinaRO [2]", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	opBuf[0] = 0xC2;
	opBuf[1] = 0x08;
	opBuf[2] = 0x00;

	if( !WriteProcessMemory(proc, *(void**)&readBuf[0], opBuf, 3, NULL) ) {
		MessageBox(NULL, "Failed to patch DestinaRO", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	if( !VirtualProtectEx(proc, *(void**)&readBuf[0], 3, oldProtect, &PID) ) {
		MessageBox(NULL, "Failed to attach to DestinaRO [2]", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

#elif STEP == DO_DIFF

	if( !ReadProcessMemory(proc, 0x4d91b0, readBuf, 3, NULL) ) {
		MessageBox(NULL, "Failed to read DestinaRO", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	printf("%u %u %u oo\n", readBuf[0], readBuf[1], readBuf[2]);

#elif STEP == DO_FINAL

	if( !VirtualProtectEx(proc, 0x4d91b0, 3, PAGE_EXECUTE_READWRITE, &oldProtect) ) {
		MessageBox(NULL, "Failed to attach to DestinaRO [2]", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	opBuf[0] = 0xC2;
	opBuf[1] = 0x08;
	opBuf[2] = 0x00;

	if( !WriteProcessMemory(proc, 0x4d91b0, opBuf, 3, NULL) ) {
		MessageBox(NULL, "Failed to patch DestinaRO", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

	if( !VirtualProtectEx(proc, 0x4d91b0, 3, oldProtect, &PID) ) {
		MessageBox(NULL, "Failed to attach to DestinaRO [2]", "Error", MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
		return 1;
	}

#endif

	CloseHandle(proc);

	MessageBox(NULL, "Success.", "DestinaRO", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);

	return 0;
}
