#include <windows.h>
#include <stdio.h>

#pragma warning (disable: 4311) // disable pointer truncation warnings

// return value in eax
DWORD calcHash(char* funcname)
{
	__asm
	{
		push esi
		push ebx
		mov esi,[funcname]

		xor ebx,ebx
		lodsb
	calcloop:
		xor bl,al
		rol ebx,6
		lodsb
		test al,al
		jnz calcloop

		mov eax,ebx
		pop ebx
		pop esi
	}
}

void* getProcAddressByHash(char* dllname,DWORD hash)
{
	char* libmem;
	PIMAGE_DOS_HEADER pDH;
	PIMAGE_NT_HEADERS pNTH;
	PIMAGE_EXPORT_DIRECTORY pIED;
	PSTR *pNames;
	PSTR pName;
	int j;
	DWORD ordinal;
	void *procaddr;

	libmem = (char*)LoadLibrary((LPCSTR)dllname);

	printf(" library %s: ",dllname);

	pDH = (PIMAGE_DOS_HEADER)libmem;
	pNTH = (PIMAGE_NT_HEADERS)(libmem + pDH->e_lfanew);
	pIED = (PIMAGE_EXPORT_DIRECTORY)(libmem + pNTH->OptionalHeader.DataDirectory[0].VirtualAddress);
	pNames = (PSTR*)(libmem + pIED->AddressOfNames);

	procaddr = NULL;
	pName = (PSTR)(libmem + (DWORD)(*pNames));
	for (j=0;j<(int)pIED->NumberOfNames;j++)
	{
		ordinal = calcHash(pName);
		if (ordinal == hash)
		{
			procaddr = GetProcAddress((HMODULE)libmem,(LPCSTR)pName);
			break;
		}
		pNames++;
		pName = (PSTR)(libmem + (DWORD)(*pNames));
	}

	printf("%08x -> %s ( %08x )\n",hash,pName,(DWORD)procaddr);

	FreeLibrary((HMODULE)libmem);
	return procaddr;
}

void findOrdinals(char* libmem)
{
	PIMAGE_DOS_HEADER pDH;
	PIMAGE_NT_HEADERS pNTH;
	PIMAGE_EXPORT_DIRECTORY pIED;
	PSTR *pNames;
	PSTR pName;
	DWORD ordinal;
	DWORD j,k;
	bool used;
	DWORD ordinalused[1024];
	char* ordinalname[1024];
	DWORD ordcount=0;

	pDH = (PIMAGE_DOS_HEADER)libmem;
	pNTH = (PIMAGE_NT_HEADERS)(libmem + pDH->e_lfanew);
	pIED = (PIMAGE_EXPORT_DIRECTORY)(libmem + pNTH->OptionalHeader.DataDirectory[0].VirtualAddress);
	pNames = (PSTR*)(libmem + pIED->AddressOfNames);

	for (j=0;j<(int)pIED->NumberOfNames;j++)
	{
		pName = (PSTR)(libmem + (DWORD)(*pNames));
		ordinal = calcHash(pName);
		printf(" . function %s\n",pName);
		used = false;
		for (k=0;k<ordcount && !used;k++)
		{
			used = ordinalused[k]==ordinal;
			if (used) break;
		}
		if (used)
			printf("   hash     %08x used by %s\n",ordinal,ordinalname[k]);
		else
		{
			printf("   hash     %08x\n",ordinal);
			ordinalname[ordcount] = pName;
			ordinalused[ordcount] = ordinal;
			ordcount++;
		}
		pNames++;
	}
}

void importbyhash(char* dllname)
{
	char* library;

	printf(" library %s\n",dllname);
	library = (char*)LoadLibrary((LPCSTR)dllname);
	if (library!=NULL)
	{
		findOrdinals(library);
		FreeLibrary((HMODULE)library);
	}
	printf("\n");
}

void main(void)
{
	importbyhash("d3d9.dll");
	importbyhash("opengl32.dll");
	importbyhash("winmm.dll");
	importbyhash("gdi32.dll");
	importbyhash("crtdll.dll");
	importbyhash("user32.dll");
	importbyhash("kernel32.dll");

	getProcAddressByHash("d3d9.dll",0x7adfb1f3); // Direct3D9Create
	getProcAddressByHash("winmm.dll",0xafdeb16e); // PlaySoundA
	getProcAddressByHash("gdi32.dll",0x12345678); // ???, should return NULL
}
