/*
 * Collin Mulliner <collin AT mulliner.org> http://www.mulliner.org/security/windows/ 
 *
 * DLL to be injected into process at startup and is able to hijack the program's entrypoint
 *
 */

#include "stdafx.h"
#include <stdio.h>
#include <fcntl.h>
#include <Windows.h>
#include <Psapi.h>

static unsigned char entrypoint[12];
static ULONG_PTR ep_ptr;

/*
 *  this endless loop will be placed at the program's entrypoint by the injection code
 *  the DLLs entrypoint will overwrite the value (0x00) of the first instruction with the address of the hook_jump() function
 *  on the next loop iteration the loop will terminate and the hook_jump() function will be executed
 */
/*
void __declspec() loop_it()
{
	_asm
	{
	_test:
		mov eax, 0x00000000;
		cmp eax, 0x00000000;
		je _test;
		jmp eax;
	}
}
*/

void entrypoint_hook()
{
	// this is the program's entrypoint
	
	// do stuff

	// remove entrypoint hook
	installhook(0);

	// on function end the process will execute it's entrypoint and will run normally
}

int read_ep_code()
{
	char fname[100] = { 0 };
	sprintf(fname, "ep_%d.bin", GetCurrentProcessId());
	int fp = open(fname, O_RDONLY);
	if (fp != -1) {
		read(fp, entrypoint, 12);
		close(fp);
		remove(fname);
		return 1;
	}
	return 0;
}

// execute entrypoint_hook and on return execute real entrypoint (that was hopefuly restored by the hook function)
void __declspec() hook_jump()
{
	_asm
	{
		push ebp;
		mov ebp, esp;
		call entrypoint_hook;
		pop ebp;
		mov eax, ep_ptr;
		jmp eax;
		ret;
	}
}

int installhook(int hook)
{
	HANDLE pid = GetCurrentProcess();
	MODULEINFO modinfo;

	if (GetModuleInformation(pid, 0, &modinfo, sizeof(modinfo))) {
		// install hook
		if (hook == 1) {
			ep_ptr = (unsigned int)modinfo.EntryPoint;
			unsigned int addrhooklabel = (unsigned int)hook_jump;
			DWORD oldp;
			VirtualProtect(modinfo.EntryPoint, 12, PAGE_EXECUTE_READWRITE, &oldp);
			unsigned char *eppc = (unsigned char*)modinfo.EntryPoint;
			eppc++;
			unsigned int *epp = (unsigned int*)eppc;
			*epp = addrhooklabel;
			DWORD oldp2;
			VirtualProtect(modinfo.EntryPoint, 12, oldp, &oldp2);
		}
		// remove hook
		else {
			// read saved entrypoint from disk, we could also read the program's binary on disk
			read_ep_code(1);

			DWORD oldp;
			VirtualProtect(modinfo.EntryPoint, 12, PAGE_EXECUTE_READWRITE, &oldp);
			memcpy(modinfo.EntryPoint, entrypoint, 12);
			DWORD oldp2;
			VirtualProtect(modinfo.EntryPoint, 12, oldp, &oldp2);
		}

		return 1;
	}

	return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call) {
	case DLL_PROCESS_ATTACH:
		if (installhook(1) == 0)
			return FALSE;
		break;
	}
	return TRUE;
}