// launcherdll.cpp
//
// Wednesday, March 18, 2009 (Melekor)
// initial version.
//

#include <windows.h>

#pragma optimize("gsy",on)
#pragma comment(linker,"/ENTRY:DllMain")
#pragma comment(linker,"/base:0x3000000")

static int tolower(int c)
{
	if(c >= 'A' && c <= 'Z')
		return c - 'A' + 'a';
	else
		return c;
}

static int strcmpi(const char* src1, const char* src2)
{
	int ret;
	while(!(ret = tolower(*src1) - tolower(*src2)) && *src2)
		++src1, ++src2;
	return ret;
}

/* patchIAT routine found at http://forum.sysinternals.com/forum_posts.asp?TID=13138 */
DWORD WINAPI patchIAT(HMODULE hMod, PROC origFunc, PROC newFunc)
{
	PIMAGE_DOS_HEADER pDosH;
	PIMAGE_NT_HEADERS pNTH;
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
	PIMAGE_THUNK_DATA pThunk;

	if(!newFunc || !hMod)
		return 0;

	// Verify that the newFunc is valid
	if (IsBadCodePtr(newFunc))
		return 0;

	// Get DOS Header
	pDosH = (PIMAGE_DOS_HEADER) hMod;

	// Verify that the PE is valid by checking e_magic's value and DOS Header size
	if(IsBadReadPtr(pDosH, sizeof(IMAGE_DOS_HEADER)))
		return 0;

	if(pDosH->e_magic != IMAGE_DOS_SIGNATURE)
		return 0;

	// Find the NT Header by using the offset of e_lfanew value from hMod
	pNTH = (PIMAGE_NT_HEADERS) ((DWORD) pDosH + (DWORD) pDosH->e_lfanew);

	// Verify that the NT Header is correct
	if(IsBadReadPtr(pNTH, sizeof(IMAGE_NT_HEADERS)))
		return 0;

	if(pNTH->Signature != IMAGE_NT_SIGNATURE)
		return 0;

	// iat patching
	pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ((DWORD) pDosH + 
		(DWORD) (pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));

	if(pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR) pNTH)
		return 0;

	while(pImportDesc->Name)
	{
		// pImportDesc->Name gives the name of the module, so we can find "kernel32.dll"
		char *name = (char *) ((DWORD) pDosH + (DWORD) (pImportDesc->Name));
		// stricmp returns 0 if strings are equal, case insensitive
		if(strcmpi(name, "kernel32.dll") == 0)
		{
			pThunk = (PIMAGE_THUNK_DATA)((DWORD) pDosH + (DWORD) pImportDesc->FirstThunk);
			while(pThunk->u1.Function)
			{
				// get the pointer of the imported function and see if it matches up with the original
				if((DWORD) pThunk->u1.Function == (DWORD) origFunc)
				{
					MEMORY_BASIC_INFORMATION mbi;
					DWORD oldProt;
					VirtualQuery(&pThunk->u1.Function, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
					VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &oldProt);
					pThunk->u1.Function = (DWORD) newFunc;
					VirtualProtect(mbi.BaseAddress, mbi.RegionSize, oldProt, &oldProt);
					break;
				}
				else
				{
					++pThunk;
				}      
			}
		}

		++pImportDesc;
	}

	return 0;      
}

void WINAPI MyGlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
{
	const DWORD dumb = 64*1024*1024;
	lpBuffer->dwLength = sizeof(MEMORYSTATUS);
	lpBuffer->dwMemoryLoad = dumb;
	lpBuffer->dwTotalPhys = dumb;
	lpBuffer->dwAvailPhys = dumb;
	lpBuffer->dwTotalPageFile = dumb;
	lpBuffer->dwAvailPageFile = dumb;
	lpBuffer->dwTotalVirtual = dumb;
	lpBuffer->dwAvailVirtual = dumb;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	if(fdwReason == DLL_PROCESS_ATTACH)
	{
		patchIAT(GetModuleHandle(NULL),(PROC)&GlobalMemoryStatus,(PROC)&MyGlobalMemoryStatus); 
	}

	return TRUE;
}
