Exemple #1
0
BOOL thcrap_inject_into_new(const char *exe_fn, char *args, const char *run_cfg_fn)
{
	int ret = 0;
	json_t *run_cfg = json_load_file_report(run_cfg_fn);
	if(!run_cfg) {
		return 1;
	};
	json_object_set_new(run_cfg, "run_cfg_fn", json_string(run_cfg_fn));
	runconfig_set(run_cfg);
	{
		STRLEN_DEC(exe_fn);
		VLA(char, exe_dir_local, exe_fn_len);
		VLA(char, exe_fn_local, exe_fn_len);
		STARTUPINFOA si = {0};
		PROCESS_INFORMATION pi = {0};
		char *exe_dir = NULL;

		strcpy(exe_fn_local, exe_fn);
		str_slash_normalize_win(exe_fn_local);

		strcpy(exe_dir_local, exe_fn);
		if(PathRemoveFileSpec(exe_dir_local)) {
			exe_dir = exe_dir_local;
		}

		/**
		  * Sure, the alternative would be to set up the entire engine
		  * with all plug-ins and modules to correctly run any additional
		  * detours. While it would indeed be nice to allow those to control
		  * initial startup, it really shouldn't be necessary for now - and
		  * it really does run way too much unnecessary code for my taste.
		  */
		ret = W32_ERR_WRAP(inject_CreateProcessU(
			exe_fn_local, args, NULL, NULL, TRUE, 0, NULL, exe_dir, &si, &pi
		));
		if(ret) {
			char *msg_str = "";

			FormatMessage(
				FORMAT_MESSAGE_FROM_SYSTEM |
				FORMAT_MESSAGE_ALLOCATE_BUFFER |
				FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL, ret, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPSTR)&msg_str, 0, NULL
			);

			log_mboxf(NULL, MB_OK | MB_ICONEXCLAMATION,
				"Failed to start %s: %s",
				exe_fn, msg_str
			);
			LocalFree(msg_str);
		}
		VLA_FREE(exe_fn_local);
		VLA_FREE(exe_dir_local);
	}
	return ret;
}
Exemple #2
0
int CreateShortcuts(const char *run_cfg_fn, json_t *games)
{
#ifdef _DEBUG
	const char *loader_exe = "thcrap_loader_d.exe";
#else
	const char *loader_exe = "thcrap_loader.exe";
#endif
	int ret = 0;
	size_t self_fn_len = GetModuleFileNameU(NULL, NULL, 0) + 1;
	VLA(char, self_fn, self_fn_len);

	GetModuleFileNameU(NULL, self_fn, self_fn_len);
	PathRemoveFileSpec(self_fn);
	PathAddBackslashA(self_fn);

	// Yay, COM.
	CoInitializeEx(NULL, COINIT_MULTITHREADED);
	{
		const char *key = NULL;
		json_t *cur_game = NULL;
		VLA(char, self_path, self_fn_len);
		strcpy(self_path, self_fn);

		strcat(self_fn, loader_exe);

		log_printf("Creating shortcuts");

		json_object_foreach(games, key, cur_game) {
			const char *game_fn = json_string_value(cur_game);
			const char *link_fn = strings_sprintf(LINK_FN, "%s (%s).lnk", key, run_cfg_fn);
			const char *link_args = strings_sprintf(LINK_ARGS, "\"%s.js\" %s", run_cfg_fn, key);

			log_printf(".");

			if(
				CreateLink(link_fn, self_fn, link_args, self_path, game_fn)
				&& !file_write_error(link_fn)
			) {
				ret = 1;
				break;
			}
		}
		VLA_FREE(self_path);
	}
	VLA_FREE(self_fn);
	CoUninitialize();
	return ret;
}
Exemple #3
0
int BP_gentext(x86_reg_t *regs, json_t *bp_info)
{
	gentext_cache_t *gc = gc_tls_get();

	// Parameters
	// ----------
	json_t *strs = json_object_get(bp_info, "str");
	const char *file = json_object_get_string(bp_info, "file");
	json_t *ids = json_object_get(bp_info, "ids");
	json_t *line_obj = json_object_get(bp_info, "line");
	// ----------
	if(file) {
		gc->file = jsondata_game_get(file);
	}
	if(ids) {
		const size_t value_len = DECIMAL_DIGITS_BOUND(size_t);
		size_t key_new_len = value_len * json_flex_array_size(ids) + 1;
		VLA(char, key_new, key_new_len);
		char *p = key_new;
		size_t i;
		json_t *id;
		json_flex_array_foreach(ids, i, id) {
			char id_str[value_len + 1];
			const char *q = id_str;
			size_t id_val = json_immediate_value(id, regs);
			snprintf(id_str, sizeof(id_str), "%u", id_val);
			if(i > 0) {
				*p++ = '_';
			}
			while(*p++ = *q++);
			p--;
		}
		gentext_cache_key_set(gc, key_new, key_new_len);
		VLA_FREE(key_new);
	}
Exemple #4
0
int binhack_render(BYTE *binhack_buf, size_t target_addr, const char *binhack_str)
{
	const char *c = binhack_str;
	const char *fs = NULL; // function start
	size_t written = 0;
	int func_rel = 0; // Relative function pointer flag
	char conv[3];
	int ret = 0;

	if(!binhack_buf || !binhack_str) {
		return -1;
	}

	conv[2] = 0;
	while(*c) {
		if(!fs && is_valid_hex(*c) && is_valid_hex(*(c+1)) ) {
			memcpy(conv, c, 2);
			*binhack_buf = (char)strtol(conv, NULL, 16);

			binhack_buf++;
			c++;
			written++;
		}
		else if(*c == '[' || *c == '<') {
			if(fs) {
				log_printf("ERROR: Nested function pointers near %s!\n", c);
				return 0;
			}
			func_rel = (*c == '[');
			fs = c + 1;
		}
		else if(fs && (*c == ']' || *c == '>')) {
			VLA(char, function, (c - fs) + 1);
			size_t fp = 0;

			strncpy(function, fs, c - fs);
			function[c - fs] = 0;

			fp = (size_t)func_get(function);
			if(fp) {
				if(func_rel) {
					fp -= target_addr + written + sizeof(void*);
				}
				memcpy(binhack_buf, &fp, sizeof(void*));
				binhack_buf += sizeof(void*);
				written += sizeof(void*);
			} else {
				log_printf("ERROR: No pointer for function '%s'...\n", function);
				ret = 2;
			}
			fs = NULL;
			VLA_FREE(function);
			if(ret) {
				break;
			}
		}
		c++;
	}
Exemple #5
0
int thcrap_inject_into_running(HANDLE hProcess, const char *run_cfg_fn)
{
	int ret = -1;
	HMODULE inj_mod = NULL;

	if(GetModuleHandleEx(
		GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
		(LPTSTR)thcrap_inject_into_running,
		&inj_mod
	)) {
		size_t cur_dir_len = GetCurrentDirectory(0, NULL) + 1;
		size_t inj_dir_len = GetModuleFileNameU(inj_mod, NULL, 0) + 1;
		VLA(char, inj_dll, inj_dir_len);
		VLA(char, inj_dir, inj_dir_len);

		STRLEN_DEC(run_cfg_fn);
		size_t param_len = cur_dir_len + run_cfg_fn_len;
		VLA(char, abs_run_cfg_fn, param_len);
		const char *param;

		GetModuleFileNameU(inj_mod, inj_dir, inj_dir_len);
		strncpy(inj_dll, inj_dir, inj_dir_len);
		PathRemoveFileSpec(inj_dir);
		PathAddBackslashA(inj_dir);

		// Allow for relative directory names
		if(PathIsRelativeA(run_cfg_fn)) {
			GetCurrentDirectory(cur_dir_len, abs_run_cfg_fn);
			PathAppendA(abs_run_cfg_fn, run_cfg_fn);
			param = abs_run_cfg_fn;
		} else {
			param = run_cfg_fn;
			param_len = run_cfg_fn_len;
		}
		ret = Inject(hProcess, inj_dir, inj_dll, "thcrap_init", param, param_len);
		VLA_FREE(abs_run_cfg_fn);
		VLA_FREE(inj_dir);
		VLA_FREE(inj_dll);
	}
	return ret;
}
Exemple #6
0
static int zip_file_extra_read(zip_file_info_t *file, zip_t *zip, int extra_len)
{
	assert(file);
	assert(zip);

	VLA(char, extra_buf, extra_len);
	DWORD byte_ret;
	int ret = W32_ERR_WRAP(ReadFile(
		zip->hArc, extra_buf, extra_len, &byte_ret, NULL
	));
	if(!ret) {
		zip_file_extra_parse(file, extra_buf, byte_ret);
	}
	VLA_FREE(extra_buf);
	return 0;
}
Exemple #7
0
int binhack_render(BYTE *binhack_buf, size_t target_addr, const char *binhack_str)
{
	const char *c = binhack_str;
	const char *fs = NULL; // function start
	size_t written = 0;
	int func_rel = 0; // Relative function pointer flag
	int ret = 0;

	if(!binhack_buf || !binhack_str) {
		return -1;
	}

	while(*c) {
		if(*c == '[' || *c == '<') {
			if(fs) {
				log_printf("ERROR: Nested function pointers near %s!\n", c);
				return 0;
			}
			func_rel = (*c == '[');
			fs = c + 1;
			c++;
		} else if(fs && (*c == ']' || *c == '>')) {
			VLA(char, function, (c - fs) + 1);
			defer({ VLA_FREE(function); });
			size_t fp = 0;

			strncpy(function, fs, c - fs);
			function[c - fs] = 0;

			fp = (size_t)func_get(function);
			if(fp) {
				if(func_rel) {
					fp -= target_addr + written + sizeof(void*);
				}
				memcpy(binhack_buf, &fp, sizeof(void*));
				binhack_buf += sizeof(void*);
				written += sizeof(void*);
			} else {
				return hackpoints_error_function_not_found(function, 2);
			}
			fs = NULL;
			if(ret) {
				break;
			}
			c++;
		} else if(fs) {
Exemple #8
0
json_t* patch_bootstrap(const json_t *sel, json_t *repo_servers)
{
	const char *main_fn = "patch.js";
	char *patch_js_buffer;
	DWORD patch_js_size;
	json_t *patch_info = patch_build(sel);
	const json_t *patch_id = json_array_get(sel, 1);
	size_t patch_len = json_string_length(patch_id) + 1;

	size_t remote_patch_fn_len = patch_len + 1 + strlen(main_fn) + 1;
	VLA(char, remote_patch_fn, remote_patch_fn_len);
	sprintf(remote_patch_fn, "%s/%s", json_string_value(patch_id), main_fn);

	patch_js_buffer = (char*)ServerDownloadFile(repo_servers, remote_patch_fn, &patch_js_size, NULL);
	patch_file_store(patch_info, main_fn, patch_js_buffer, patch_js_size);
	// TODO: Nice, friendly error

	VLA_FREE(remote_patch_fn);
	SAFE_FREE(patch_js_buffer);
	return patch_info;
}
Exemple #9
0
char* console_read(char *str, int n)
{
	int ret;
	int i;
	fgets(str, n, stdin);
	{
		// Ensure UTF-8
		VLA(wchar_t, str_w, n);
		StringToUTF16(str_w, str, n);
		StringToUTF8(str, str_w, n);
		VLA_FREE(str_w);
	}
	// Get rid of the \n
	for(i = 0; i < n; i++) {
		if(str[i] == '\n') {
			str[i] = 0;
			return str;
		}
	}
	while((ret = getchar()) != '\n' && ret != EOF);
	return str;
}
Exemple #10
0
/// Indexing helpers
/// ----------------
// Adds an individual zipped file to the index.
// Expects the file name at the current file pointer of [zip->hArc].
static int zip_file_add(zip_t *zip, zip_file_shared_t *zf, json_int_t offset)
{
	int ret = -1;
	if(zip && zf) {
		DWORD byte_ret;
		VLA(char, fn, zf->fn_len + 1);
		ReadFile(zip->hArc, fn, zf->fn_len, &byte_ret, NULL);
		fn[zf->fn_len] = 0;
		SetFilePointer(zip->hArc, zf->extra_len, NULL, FILE_CURRENT);
		if(zf->fn_len) {
			if(zf->size_compressed != 0) {
				json_object_set_new(zip->files, fn, json_integer(offset));
			} else {
				char last = fn[zf->fn_len - 1];
				if(last != '/' && last != '\\') {
					json_array_append_new(zip->files_empty, json_string(fn));
				}
			}
		}
		VLA_FREE(fn);
		ret = 0;
	}
Exemple #11
0
static LRESULT CALLBACK loader_update_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static loader_update_state_t *state = nullptr;

	switch (uMsg) {
	case WM_CREATE: {
		CREATESTRUCTW *param = (CREATESTRUCTW*)lParam;
		state = (loader_update_state_t*)param->lpCreateParams;
		break;
	}

	case WM_COMMAND:
		switch LOWORD(wParam) {
		case HWND_BUTTON_RUN:
			if (HIWORD(wParam) == BN_CLICKED) {
				if (state->background_updates == false) {
					state->cancel_update = true;
				}
				EnterCriticalSection(&state->cs);
				state->game_started = true;
				LeaveCriticalSection(&state->cs);
				thcrap_inject_into_new(state->exe_fn, state->args, NULL, NULL);
			}
			break;

		case HWND_BUTTON_UPDATE:
			if (HIWORD(wParam) == BN_CLICKED) {
				SetEvent(state->event_require_update);
			}
			break;

		case HWND_CHECKBOX_KEEP_UPDATER:
			if (HIWORD(wParam) == BN_CLICKED) {
				BOOL enable_state;
				if (SendMessage(state->hwnd[HWND_CHECKBOX_KEEP_UPDATER], BM_GETCHECK, 0, 0) == BST_CHECKED) {
					state->background_updates = true;
					enable_state = TRUE;
				}
				else {
					state->background_updates = false;
					enable_state = FALSE;
				}
				EnableWindow(state->hwnd[HWND_STATIC_UPDATES_INTERVAL], enable_state);
				EnableWindow(state->hwnd[HWND_EDIT_UPDATES_INTERVAL], enable_state);
				EnableWindow(state->hwnd[HWND_UPDOWN], enable_state);
			}
			break;

		case HWND_EDIT_UPDATES_INTERVAL:
			if (HIWORD(wParam) == EN_CHANGE) {
				BOOL success;
				UINT n = GetDlgItemInt(state->hwnd[HWND_MAIN], HWND_EDIT_UPDATES_INTERVAL, &success, FALSE);
				if (success) {
					EnterCriticalSection(&state->cs);
					state->time_between_updates = n;
					LeaveCriticalSection(&state->cs);
				}
			}
			break;

		case HWND_CHECKBOX_UPDATE_AT_EXIT:
			if (HIWORD(wParam) == BN_CLICKED) {
				if (SendMessage(state->hwnd[HWND_CHECKBOX_UPDATE_AT_EXIT], BM_GETCHECK, 0, 0) == BST_CHECKED) {
					state->update_at_exit = true;
				}
				else {
					state->update_at_exit = false;
				}
			}
			break;

		case HWND_CHECKBOX_UPDATE_OTHERS:
			if (HIWORD(wParam) == BN_CLICKED) {
				if (SendMessage(state->hwnd[HWND_CHECKBOX_UPDATE_OTHERS], BM_GETCHECK, 0, 0) == BST_CHECKED) {
					state->update_others = true;
				}
				else {
					state->update_others = false;
				}
			}
			break;

		case HWND_BUTTON_DISABLE_UPDATES:
			if (HIWORD(wParam) == BN_CLICKED) {
				int len = GetCurrentDirectory(0, NULL);
				VLA(char, current_directory, len + 1);
				GetCurrentDirectory(len + 1, current_directory);
				if (log_mboxf(NULL, MB_YESNO, "Do you really want to completely disable updates?\n\n"
					"If you want to enable them again, you will need to run\n"
					"%s\\thcrap_enable_updates.bat",
					current_directory) == IDYES) {
					MoveFile("thcrap_update" DEBUG_OR_RELEASE ".dll", "thcrap_update_disabled" DEBUG_OR_RELEASE ".dll");
					const char *bat_file =
						"@echo off\n"
						"if not exist \"%~dp0\"\\thcrap_update" DEBUG_OR_RELEASE ".dll (\n"
						"move \"%~dp0\"\\thcrap_update_disabled" DEBUG_OR_RELEASE ".dll \"%~dp0\"\\thcrap_update" DEBUG_OR_RELEASE ".dll\n"
						"echo Updates enabled\n"
						") else (\n"
						"echo Updates are already enabled\n"
						")\n"
						"pause\n"
						"(goto) 2>nul & del \"%~f0\"\n";
					file_write("thcrap_enable_updates.bat", bat_file, strlen(bat_file));
					log_mbox(NULL, MB_OK, "Updates are now disabled.");
					PostQuitMessage(0);
				}
				VLA_FREE(current_directory);
			}
			break;

		case HWND_BUTTON_EXPAND_LOGS:
			if (HIWORD(wParam) == BN_CLICKED) {
				if (state->settings_visible) {
					// Hide log window
					SetWindowPos(state->hwnd[HWND_MAIN], 0, 0, 0, 500, 165, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
					state->settings_visible = false;
				}
				else {
					// Show log window
					SetWindowPos(state->hwnd[HWND_MAIN], 0, 0, 0, 500, 435, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
					state->settings_visible = true;
				}
			}
			break;
		}
		break;

	case WM_CTLCOLORSTATIC:
		if ((HWND)lParam == state->hwnd[HWND_LABEL_STATUS] ||
			(HWND)lParam == state->hwnd[HWND_CHECKBOX_UPDATE_AT_EXIT] ||
			(HWND)lParam == state->hwnd[HWND_CHECKBOX_KEEP_UPDATER] ||
			(HWND)lParam == state->hwnd[HWND_CHECKBOX_UPDATE_OTHERS] ||
			(HWND)lParam == state->hwnd[HWND_STATIC_UPDATES_INTERVAL] ||
			(HWND)lParam == state->hwnd[HWND_STATIC_UPDATE_AT_EXIT]) {
			HDC hdc = (HDC)wParam;
			SetTextColor(hdc, RGB(0, 0, 0));
			SetBkMode(hdc, TRANSPARENT);
			return (LRESULT)GetSysColorBrush(COLOR_WINDOW);
		}
		break;

	case WM_DESTROY:
		state->cancel_update = true;
		PostQuitMessage(0);
		break;
	}
Exemple #12
0
int Inject(HANDLE hProcess, const char *dll_dir, const char *dll_fn, const char *func_name, const void *param, const size_t param_size)
{
	// String constants
	const char *injectError1Format =
		"Could not inject %s.\n"
		"\n"
		"If you're running Windows Vista or 7, make sure that you have installed the KB2533623 update:\n"
		"\n"
		"\thttp://support.microsoft.com/kb/2533623/";
	const char *injectError2Format = "Could not load the function: %s";

//------------------------------------------//
// Function variables.                      //
//------------------------------------------//

	// Main DLL we will need to load
	HMODULE kernel32 = GetModuleHandleA("kernel32.dll");

	// Main functions we will need to import.
	// If [dll_fn] is absolute, LoadLibraryEx() with the LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
	// flag is used to guarantee that the injected DLL and its dependencies really
	// are only loaded from the given directory. Otherwise, LoadLibrary() may load
	// a possible other DLL with the same name from the directory of [hProcess].
	FARPROC getcurrentdirectory = GetProcAddress(kernel32, "GetCurrentDirectoryW");
	FARPROC setcurrentdirectory = GetProcAddress(kernel32, "SetCurrentDirectoryW");
	FARPROC loadlibrary = GetProcAddress(kernel32, "LoadLibraryW");
	FARPROC loadlibraryex = GetProcAddress(kernel32, "LoadLibraryExW");
	FARPROC getprocaddress = GetProcAddress(kernel32, "GetProcAddress");
	FARPROC exitthread = GetProcAddress(kernel32, "ExitThread");
	FARPROC freelibraryandexitthread = GetProcAddress(kernel32, "FreeLibraryAndExitThread");
	int have_kb2269637 = GetProcAddress(kernel32, "SetDefaultDllDirectories") != 0;

	// The workspace we will build the codecave on locally.
	// workspaceSize gets incremented with the final length of the error strings.
	size_t workspaceSize = 2048;
	LPBYTE workspace = NULL;
	LPBYTE p = NULL;

	// The memory in the process we write to
	LPBYTE codecaveAddress = NULL;

	// Strings we have to write into the process
	size_t injectError1_len = _scprintf(injectError1Format, dll_fn) + 1;
	size_t injectError2_len = _scprintf(injectError2Format, func_name) + 1;

	char *injectError0 = "Error";
	VLA(char, injectError1, injectError1_len);
	VLA(char, injectError2, injectError2_len);
	char *user32Name = "user32.dll";
	char *msgboxName = "MessageBoxW";

	// Placeholder addresses to use the strings
	LPBYTE user32NameAddr = 0;
	LPBYTE user32Addr = 0;
	LPBYTE msgboxNameAddr = 0;
	LPBYTE msgboxAddr = 0;
	LPBYTE dllAddr = 0;
	LPBYTE dllDirAddr = 0;
	LPBYTE dllNameAddr = 0;
	LPBYTE funcNameAddr = 0;
	LPBYTE funcParamAddr = 0;
	LPBYTE error0Addr = 0;
	LPBYTE error1Addr = 0;
	LPBYTE error2Addr = 0;

	// Where the codecave execution should begin at
	LPTHREAD_START_ROUTINE codecaveExecAddr = 0;

	// Handle to the thread we create in the process
	HANDLE hThread = NULL;

	// Old protection on page we are writing to in the process and the bytes written
	DWORD oldProtect = 0;
	DWORD byte_ret = 0;

	// Return code of injection function
	DWORD injRet;

//------------------------------------------//
// Variable initialization.                 //
//------------------------------------------//

// This section will cause compiler warnings on VS8,
// you can upgrade the functions or ignore them

	// Build error messages
	sprintf(injectError1, injectError1Format, dll_fn);
	sprintf(injectError2, injectError2Format, func_name);

	workspaceSize += (
		strlen(dll_dir) + 1 + strlen(dll_fn) + 1 + strlen(func_name) + 1 +
		param_size + strlen(injectError1) + 1 + strlen(injectError2) + 1
	) * sizeof(wchar_t);

	// Create the workspace
	workspace = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, workspaceSize);
	p = workspace;

	// Allocate space for the codecave in the process
	codecaveAddress = (LPBYTE)VirtualAllocEx(hProcess, 0, workspaceSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

// Note there is no error checking done above for any functions that return a pointer/handle.
// I could have added them, but it'd just add more messiness to the code and not provide any real
// benefit. It's up to you though in your final code if you want it there or not.

//------------------------------------------//
// Data and string writing.                 //
//------------------------------------------//

	// Reserve space for the user32 dll address, the MessageBox address,
	// and the address of the injected DLL's module.
	user32Addr = (p - workspace) + codecaveAddress;
	p += sizeof(LPBYTE);

	msgboxAddr = (p - workspace) + codecaveAddress;
	p += sizeof(LPBYTE);

	dllAddr = (p - workspace) + codecaveAddress;
	p += sizeof(LPBYTE);

	// User32 Dll Name
	user32NameAddr = (p - workspace) + codecaveAddress;
	p = StringToUTF16_advance_dst(p, user32Name);

	// MessageBox name
	msgboxNameAddr = (p - workspace) + codecaveAddress;
	p = memcpy_advance_dst(p, msgboxName, strlen(msgboxName) + 1);

	// Directory name
	if(dll_dir) {
		dllDirAddr = (p - workspace) + codecaveAddress;
		p = StringToUTF16_advance_dst(p, dll_dir);
	}

	// Dll Name
	dllNameAddr = (p - workspace) + codecaveAddress;
	p = StringToUTF16_advance_dst(p, dll_fn);

	// Function Name
	funcNameAddr = (p - workspace) + codecaveAddress;
	p = memcpy_advance_dst(p, func_name, strlen(func_name) + 1);

	// Function Parameter
	funcParamAddr = (p - workspace) + codecaveAddress;
	p = memcpy_advance_dst(p, param, param_size);

	// Error Message 1
	error0Addr = (p - workspace) + codecaveAddress;
	p = StringToUTF16_advance_dst(p, injectError0);

	// Error Message 2
	error1Addr = (p - workspace) + codecaveAddress;
	p = StringToUTF16_advance_dst(p, injectError1);

	// Error Message 3
	error2Addr = (p - workspace) + codecaveAddress;
	p = StringToUTF16_advance_dst(p, injectError2);

	// Pad a few INT3s after string data is written for seperation
	*p++ = 0xCC;
	*p++ = 0xCC;
	*p++ = 0xCC;

	// Store where the codecave execution should begin
	codecaveExecAddr = (LPTHREAD_START_ROUTINE)((p - workspace) + codecaveAddress);

// For debugging - infinite loop, attach onto process and step over
	//*p++ = 0xEB;
	//*p++ = 0xFE;

//------------------------------------------//
// User32.dll loading.                      //
//------------------------------------------//

// User32 DLL Loading
	// PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibrary
	*p++ = 0x68;
	p = ptrcpy_advance_dst(p, user32NameAddr);

	// MOV EAX, ADDRESS - Move the address of LoadLibrary into EAX
	*p++ = 0xB8;
	p = ptrcpy_advance_dst(p, loadlibrary);

	// CALL EAX - Call LoadLibrary
	*p++ = 0xFF;
	*p++ = 0xD0;

// MessageBox Loading
	// PUSH 0x000000 - Push the address of the function name to load
	*p++ = 0x68;
	p = ptrcpy_advance_dst(p, msgboxNameAddr);

	// Push EAX, module to use in GetProcAddress
	*p++ = 0x50;

	// MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX
	*p++ = 0xB8;
	p = ptrcpy_advance_dst(p, getprocaddress);

	// CALL EAX - Call GetProcAddress
	*p++ = 0xFF;
	*p++ = 0xD0;

	// MOV [ADDRESS], EAX - Save the address to our variable
	*p++ = 0xA3;
	p = ptrcpy_advance_dst(p, msgboxAddr);

//------------------------------------------//
// Injected dll loading.                    //
//------------------------------------------//

/*
	// This is the way the following assembly code would look like in C/C++

	// In case the injected DLL depends on other DLLs,
	// we need to change the current directory to the one given as parameter
	if(dll_dir) {
		size_t cur_dir_len = GetCurrentDirectory(0, NULL) + 1;
		VLA(wchar_t, cur_dir, cur_dir_len);
		GetCurrentDirectory(cur_dir, cur_dir_len);
		SetCurrentDirectory(dll_dir);
	}

	// Load the injected DLL into this process
	HMODULE h = LoadLibraryEx(dll_fn, NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
	if(!h) {
		MessageBox(0, injectError1, "Error", MB_ICONERROR);
		ExitThread(1);
	}

	if(dll_dir) {
		SetCurrentDirectory(cur_dir);
	}

	// Get the address of the export function
	FARPROC p = GetProcAddress(h, func_name);
	if(!p) {
		MessageBox(0, injectError2, "Error", MB_ICONERROR);
		FreeLibraryAndExitThread(h, 2);
	}

	// So we do not need a function pointer interface
	__asm call p

	// Exit the thread so the loader continues
	ExitThread(0);
*/

// DLL Loading

	if(dllDirAddr) {
		// Registers:

		// ebp: Base stack frame
		// esi: GetCurrentDirectory / SetCurrentDirectory
		// ebx: Current directory of process (on stack)
		// ecx: byte length of string at ebx

		// mov ebp, esp - Save stack frame
		*p++ = 0x89;
		*p++ = 0xe5;

		// Get length for current directory

		// push 0
		// push 0
		*p++ = 0x6a;
		*p++ = 0x00;
		*p++ = 0x6a;
		*p++ = 0x00;
		// mov esi, GetCurrentDirectory
		*p++ = 0xbe;
		p = ptrcpy_advance_dst(p, getcurrentdirectory);

		// call esi
		*p++ = 0xFF;
		*p++ = 0xD6;

		/// Calculate byte size of directory buffer.
		/// Also do some poor man's DWORD boundary alignment
		/// in order to not f**k up the stack

		// mov ecx, eax
		// shl ecx, 1
		// and ecx, fffffff8
		// add ecx, 4

		*p++ = 0x89;
		*p++ = 0xc1;
		*p++ = 0xd1;
		*p++ = 0xe1;
		*p++ = 0x83;
		*p++ = 0xe1;
		*p++ = 0xf8;
		*p++ = 0x83;
		*p++ = 0xc1;
		*p++ = 0x04;

		/// "Allocate" ecx bytes on stack and store buffer pointer to ebx

		// sub esp, ecx
		// mov ebx, esp

		*p++ = 0x29;
		*p++ = 0xcc;
		*p++ = 0x89;
		*p++ = 0xe3;

		/// Call GetCurrentDirectory
		// push ebx
		// push eax
		// call esi
		*p++ = 0x53;
		*p++ = 0x50;
		*p++ = 0xff;
		*p++ = 0xd6;

		/// PUSH 0x00000000 - Push the address of our directory
		*p++ = 0x68;
		p = ptrcpy_advance_dst(p, dllDirAddr);

		// mov esi, SetCurrentDirectory
		*p++ = 0xbe;
		p = ptrcpy_advance_dst(p, setcurrentdirectory);

		// call esi
		*p++ = 0xFF;
		*p++ = 0xD6;
	}

	if(PathIsRelativeA(dll_fn) || !have_kb2269637) {
		// PUSH 0x00 (dwFlags = 0)
		*p++ = 0x6a;
		*p++ = 0x00;
	} else {
		// PUSH 0x00000900 (dwFlags = LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32)
		*p++ = 0x68;
		*p++ = 0x00;
		*p++ = 0x09;
		*p++ = 0x00;
		*p++ = 0x00;
	}

	// PUSH 0x00 (hFile = NULL)
	*p++ = 0x6a;
	*p++ = 0x00;

	// PUSH 0x00000000 - Push the address of the DLL name to use in LoadLibraryEx
	*p++ = 0x68;
	p = ptrcpy_advance_dst(p, dllNameAddr);

	// MOV EAX, ADDRESS - Move the address of LoadLibraryEx into EAX
	*p++ = 0xB8;
	p = ptrcpy_advance_dst(p, loadlibraryex);

	// CALL EAX - Call LoadLibraryEx
	*p++ = 0xFF;
	*p++ = 0xD0;

	// mov edi, eax - Save return value
	*p++ = 0x89;
	*p++ = 0xc7;

	if(dllDirAddr) {
		/// Reset directory to the original one of the process
		// push ebx
		// call esi
		*p++ = 0x53;
		*p++ = 0xFF;
		*p++ = 0xD6;

		/// Reset stack frame
		// mov esp, ebp
		*p++ = 0x89;
		*p++ = 0xec;
	}

// Error Checking
	// CMP EDI, 0
	*p++ = 0x83;
	*p++ = 0xFF;
	*p++ = 0x00;

// JNZ EIP + 0x1E to skip over eror code
	*p++ = 0x75;
	*p++ = 0x1E;

// Error Code 1
	// MessageBox
		// PUSH 0x10 (MB_ICONHAND)
		*p++ = 0x6A;
		*p++ = 0x10;

		// PUSH 0x000000 - Push the address of the MessageBox title
		*p++ = 0x68;
		p = ptrcpy_advance_dst(p, error0Addr);

		// PUSH 0x000000 - Push the address of the MessageBox message
		*p++ = 0x68;
		p = ptrcpy_advance_dst(p, error1Addr);

		// Push 0
		*p++ = 0x6A;
		*p++ = 0x00;

		// MOV EAX, [ADDRESS] - Move the address of MessageBox into EAX
		*p++ = 0xA1;
		p = ptrcpy_advance_dst(p, msgboxAddr);

		// CALL EAX - Call MessageBoxW
		*p++ = 0xFF;
		*p++ = 0xD0;

	// ExitThread
		// PUSH 1
		*p++ = 0x6A;
		*p++ = 0x01;

		// MOV EAX, ADDRESS - Move the address of ExitThread into EAX
		*p++ = 0xB8;
		p = ptrcpy_advance_dst(p, exitthread);

		// CALL EAX - Call ExitThread
		*p++ = 0xFF;
		*p++ = 0xD0;

//	Now we have the address of the injected DLL, so save the handle

	// MOV [ADDRESS], EAX - Save the address to our variable
	*p++ = 0x89;
	*p++ = 0x3D;
	p = ptrcpy_advance_dst(p, dllAddr);

// Load the initilize function from it

	// PUSH 0x000000 - Push the address of the function name to load
	*p++ = 0x68;
	p = ptrcpy_advance_dst(p, funcNameAddr);

	// Push EDI - module to use in GetProcAddress
	*p++ = 0x57;

	// MOV EAX, ADDRESS - Move the address of GetProcAddress into EAX
	*p++ = 0xB8;
	p = ptrcpy_advance_dst(p, getprocaddress);

	// CALL EAX - Call GetProcAddress
	*p++ = 0xFF;
	*p++ = 0xD0;

// Error Checking
	// CMP EAX, 0
	*p++ = 0x83;
	*p++ = 0xF8;
	*p++ = 0x00;

// JNZ EIP + 0x23 to skip eror code
	*p++ = 0x75;
	*p++ = 0x23;

// Error Code 2
	// MessageBox
		// PUSH 0x10 (MB_ICONHAND)
		*p++ = 0x6A;
		*p++ = 0x10;

		// PUSH 0x000000 - Push the address of the MessageBox title
		*p++ = 0x68;
		p = ptrcpy_advance_dst(p, error0Addr);

		// PUSH 0x000000 - Push the address of the MessageBox message
		*p++ = 0x68;
		p = ptrcpy_advance_dst(p, error2Addr);

		// Push 0
		*p++ = 0x6A;
		*p++ = 0x00;

		// MOV EAX, ADDRESS - Move the address of MessageBox into EAX
		*p++ = 0xA1;
		p = ptrcpy_advance_dst(p, msgboxAddr);

		// CALL EAX - Call MessageBoxA
		*p++ = 0xFF;
		*p++ = 0xD0;

	// FreeLibraryAndExitThread
		// PUSH 2
		*p++ = 0x6A;
		*p++ = 0x02;

		// PUSH 0x000000 - Push the injected DLL's module handle
		*p++ = 0x68;
		p = ptrcpy_advance_dst(p, dllAddr);

		// MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX
		*p++ = 0xB8;
		p = ptrcpy_advance_dst(p, freelibraryandexitthread);

		// CALL EAX - Call ExitThread function
		*p++ = 0xFF;
		*p++ = 0xD0;

	// PUSH 0x000000 - Push the address of the function parameter
	*p++ = 0x68;
	p = ptrcpy_advance_dst(p, funcParamAddr);

	// CALL EAX - Call [func_name]
	*p++ = 0xFF;
	*p++ = 0xD0;

	// If we get here, [func_name] has been called,
	// so it's time to close this thread and optionally unload the DLL.

//------------------------------------------//
// Exiting from the injected dll.           //
//------------------------------------------//

// Call ExitThread to leave the DLL loaded
#if 1
	// PUSH 0 (exit code)
	*p++ = 0x6A;
	*p++ = 0x00;

	// MOV EAX, ADDRESS - Move the address of ExitThread into EAX
	*p++ = 0xB8;
	p = ptrcpy_advance_dst(p, exitthread);

	// CALL EAX - Call ExitThread
	*p++ = 0xFF;
	*p++ = 0xD0;
#endif

// Call FreeLibraryAndExitThread to unload DLL
#if 0
	// Push 0 (exit code)
	*p++ = 0x6A;
	*p++ = 0x00;

	// PUSH [0x000000] - Push the address of the DLL module to unload
	*p++ = 0xFF;
	*p++ = 0x35;
	p = ptrcpy_advance_dst(p, dllAddr);

	// MOV EAX, ADDRESS - Move the address of FreeLibraryAndExitThread into EAX
	*p++ = 0xB8;
	p = ptrcpy_advance_dst(p, freelibraryandexitthread);

	// CALL EAX - Call FreeLibraryAndExitThread
	*p++ = 0xFF;
	*p++ = 0xD0;
#endif

//------------------------------------------//
// Code injection and cleanup.              //
//------------------------------------------//

	// Change page protection so we can write executable code
	VirtualProtectEx(hProcess, codecaveAddress, p - workspace, PAGE_EXECUTE_READWRITE, &oldProtect);

	// Write out the patch
	WriteProcessMemory(hProcess, codecaveAddress, workspace, p - workspace, &byte_ret);

	// Restore page protection
	VirtualProtectEx(hProcess, codecaveAddress, p - workspace, oldProtect, &oldProtect);

	// Make sure our changes are written right away
	FlushInstructionCache(hProcess, codecaveAddress, p - workspace);

	// Free the workspace memory
	HeapFree(GetProcessHeap(), 0, workspace);

	// Execute the thread now and wait for it to exit, note we execute where the code starts, and not the codecave start
	// (since we wrote strings at the start of the codecave)
	hThread = CreateRemoteThread(hProcess, NULL, 0, codecaveExecAddr, 0, 0, NULL);
	WaitForSingleObject(hThread, INFINITE);

	GetExitCodeThread(hThread, &injRet);
	CloseHandle(hThread);

	// Free the memory in the process that we allocated
	VirtualFreeEx(hProcess, codecaveAddress, 0, MEM_RELEASE);

	VLA_FREE(injectError1);
	VLA_FREE(injectError2);
	return injRet;
}