#include <windows.h>
#include <stdio.h>

typedef HINSTANCE (WINAPI *ShellExecuteProc)(HWND, LPCSTR, LPCSTR, LPCSTR, LPCSTR, INT);

ShellExecuteProc ShellExecuteFunc;

void __declspec(dllexport) Cookie() { }

inline void *rva_calc(HANDLE base, int Offset) { return (void*)((int)base + Offset); }

HINSTANCE __stdcall MyShellExecute(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd) {
	if(lpParameters == NULL)
		return ShellExecuteFunc(hwnd,lpOperation,lpFile,lpParameters,lpDirectory,nShowCmd);
	else
		return ShellExecuteFunc(hwnd,lpOperation,lpParameters,NULL,lpDirectory,nShowCmd);
}

int DoInit() {

#ifdef DEBUG
	AllocConsole();
	SetConsoleTitle("Debug");
	freopen("conin$", "r", stdin);
	freopen("conout$", "w", stdout);
	freopen("conout$", "w", stderr);
#endif

	HMODULE QipHandle = GetModuleHandle(NULL);
	
	if( QipHandle == NULL )
		return FALSE;

	DWORD Offset;
	bool Found = false;
	char *CorruptedString = "Sorry, qip.exe file is corrupted.";
	size_t CorruptedLength = strlen( CorruptedString );

	for( Offset = 0x005A0000; Offset < 0x006A0000; Offset += 4 )
	{
		if( memcmp( (void*)Offset, (void*)CorruptedString, CorruptedLength ) == 0 ) {
			Found = true;
			break;
		}
	}
	if( Found == false ) {
		printf("Unable to locate the integrity string.\n");
		return FALSE;
	}
	
	Offset = ((Offset << 8) & 0xFFFFFF00) | (0xBA & 0xFF);

	DWORD OpOffset;

	for( OpOffset = 0x005A0000; OpOffset < 0x006A0000; OpOffset++ )
	{
		if( *(DWORD*)OpOffset == Offset ) {
			Found = true;
			break;
		}
	}
	if( Found == false ) {
		printf("Unable to locate the integrity opcode.\n");
		return FALSE;
	}

	OpOffset -= 9;

	DWORD oldProtect;
	VirtualProtect( (LPVOID)OpOffset, 1, PAGE_EXECUTE_READWRITE, &oldProtect );
	*(BYTE*)OpOffset = 0xBE; // jnz -> jmp
	VirtualProtect( (LPVOID)OpOffset, 1, oldProtect, &oldProtect );

	// As the integrity check is bypassed now, hook the ShellExecute call
	PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)QipHandle;

	if( dos->e_magic != IMAGE_DOS_SIGNATURE ) {
		return FALSE;
	}

	PIMAGE_NT_HEADERS pe = (PIMAGE_NT_HEADERS)rva_calc(QipHandle, dos->e_lfanew);

	if( pe->Signature != IMAGE_NT_SIGNATURE ) {
		return FALSE;
	}

	if( pe->OptionalHeader.DataDirectory[1].VirtualAddress == NULL ) {
		return FALSE;
	}

	PIMAGE_IMPORT_DESCRIPTOR imports = (PIMAGE_IMPORT_DESCRIPTOR)rva_calc(QipHandle, pe->OptionalHeader.DataDirectory[1].VirtualAddress);

	ShellExecuteFunc = (ShellExecuteProc)GetProcAddress( GetModuleHandle("Shell32.dll"), "ShellExecuteA" );

	for(unsigned int i = 0; true; i++)
	{
		if( imports[i].Name == NULL )
				break;

		if( stricmp( (char*)rva_calc(QipHandle, imports[i].Name), "Shell32.dll" ) == 0 ) {
			PIMAGE_THUNK_DATA thunk;

			if( imports[i].OriginalFirstThunk == NULL )
				thunk = (PIMAGE_THUNK_DATA)rva_calc(QipHandle, imports[i].FirstThunk);
			else
				thunk = (PIMAGE_THUNK_DATA)rva_calc(QipHandle, imports[i].OriginalFirstThunk);

			for(unsigned int ii = 0; true; ii++)
			{
				if( thunk[ii].u1.Ordinal == (DWORD)ShellExecuteFunc ) {
					VirtualProtect( (LPVOID)&thunk[ii], 4, PAGE_EXECUTE_READWRITE, &oldProtect );
					*(DWORD*)&thunk[ii] = (DWORD)MyShellExecute;
					VirtualProtect( (LPVOID)&thunk[ii], 4, oldProtect, &oldProtect );
					printf("FOUND @ %x!!\n", &thunk[ii]);
					return TRUE;
				}
			}
		}
	}

	printf("Unable to hook ShellExecuteA\n");
	return FALSE;

}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) {
	switch(fdwReason) {
		case DLL_PROCESS_ATTACH:
			return DoInit();
	}
}

