/* Terminology:
 *
 * fish = function to patch
 * hook = patch to apply
 * coolbox = overwritten bytes and stack fixer
 * scales = memory security flags
 */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <windows.h>
#include "hooks.h"
#include "ollydisasm/disasm.h"
/*register int *stackp asm ("esp");
register int *basep  asm ("ebp");*/

unsigned long CleanBiteOff(const uint8_t *ptr, size_t amount); // how many bytes should i overwrite to fit a jump and not leave garbage behind 

int attachRawHook(uintptr_t fish, uintptr_t hook)
{

	#define JMP_SIZE 5
	unsigned long safeSize = CleanBiteOff((uint8_t*)fish, JMP_SIZE);
	
	uint8_t *overwrite = malloc(safeSize);

	overwrite[0] = 0xE9;//call e8 -- jmp e9
	for (int i = JMP_SIZE; i < safeSize; i++)
		overwrite[i] = 0x90;

	DWORD oldScales, newScales;
	//__asm("int $3");
	uint8_t* coolbox;
	#define XCHG_SIZE 13
	#define FOOTER_SIZE 2*JMP_SIZE+XCHG_SIZE
	if ((coolbox = VirtualAlloc(NULL, safeSize + FOOTER_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)) == NULL)
		return __HOOK_VIRTUALALLOC_COOLBOX;
	uintptr_t relative = (uintptr_t)coolbox + safeSize - fish;
	
	memcpy(&overwrite[1], &relative, JMP_SIZE-1);
	memcpy(coolbox, (void*)(fish), safeSize);
	relative = -relative;
	/*
	push ecx
	mov ecx, %coolbox
	xchg dword [esp+4], ecx
	xchg dword[esp], ecx

	 {0x51,0xB9,0,0,0,0,0x87,0x4C,0xE4,0x04,0x87,0x0C,0xE4}
	*/
	#define FOUR_BYTES 0,0,0,0
	uint8_t coolboxfooter[FOOTER_SIZE] = {0xE9,FOUR_BYTES,0x51,0xB9,FOUR_BYTES,0x87,0x4C,0xE4,0x04,0x87,0x0C,0xE4, 0xE9/*,FOUR_BYTES*/};
	memcpy(&coolboxfooter[1], &relative, JMP_SIZE-1);
	memcpy(&coolboxfooter[JMP_SIZE+2], &coolbox, JMP_SIZE-1);
	relative = hook - ((uintptr_t)coolbox + safeSize + FOOTER_SIZE);
	memcpy(&coolboxfooter[JMP_SIZE+XCHG_SIZE+1], &relative, JMP_SIZE-1);
	memcpy(coolbox+safeSize, coolboxfooter, FOOTER_SIZE);

	if (VirtualProtect((LPVOID) fish, safeSize, PAGE_READWRITE, &oldScales) == 0)
		return __HOOK_PROTECTION_DISABLE;

	memcpy((void*)fish, overwrite, safeSize);
	
	if (VirtualProtect((LPVOID)fish, safeSize, oldScales, &newScales) == 0)
		return __HOOK_PROTECTION_ENABLE;

	return __HOOK_ALL_OK;
	
}
unsigned long CleanBiteOff(const uint8_t *ptr, size_t amount)
{
	static t_disasm disasm;
	unsigned long size = 0;
	do {size += Disasm(ptr+size, 16, 0x00401AAC, &disasm, DISASM_SIZE);} while(size < amount);
	return size;
}