// GetProcAddress2 - by Darawk
//
// GetProcAddress2 is essentially identical to the
// windows API function GetProcAddress, with one
// key difference. GetProcAddress2 does not check
// to make sure the module handle that's passed to
// it is in the loaded modules list. GetProcAddress2
// is designed to be used in conjunction with ManualMap
// or CloakDll. It allows you to access functions that
// have been exported from a dll loaded by ManualMap or
// cloaked by CloakDll. This functionality is necessary
// for plugin-based applications and late-binding functions.
#include <windows.h>
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
// Pietrek's macro
//
// MakePtr is a macro that allows you to easily add to values (including
// pointers) together without dealing with C's pointer arithmetic. It
// essentially treats the last two parameters as DWORDs. The first
// parameter is used to typecast the result to the appropriate pointer type.
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))
// This one is mine, but obviously..."adapted" from matt's original idea =p
#define MakeDelta(cast, x, y) (cast) ( (DWORD_PTR)(x) - (DWORD_PTR)(y))
// My modified version of pietrek's function, to work with PE files that have
// already been mapped into memory.
LPVOID GetPtrFromRVA( DWORD, IMAGE_NT_HEADERS *, PBYTE, bool);
FARPROC GetProcAddress2(HMODULE hMod, char *func)
{
IMAGE_DOS_HEADER *dosHd;
IMAGE_NT_HEADERS *ntHd;
IMAGE_EXPORT_DIRECTORY *ied;
char **names;
unsigned short *ordinals;
FARPROC *funcs;
// Make sure we got a valid pointer
if(!hMod || hMod == INVALID_HANDLE_VALUE)
return NULL;
dosHd = (IMAGE_DOS_HEADER *)hMod;
// Verify the DOS header
if(dosHd->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
ntHd = MakePtr(IMAGE_NT_HEADERS *, hMod, dosHd->e_lfanew);
// Verify the NT header
if(ntHd->Signature != IMAGE_NT_SIGNATURE)
return NULL;
ied = (IMAGE_EXPORT_DIRECTORY *)GetPtrFromRVA((DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress),
ntHd,
(PBYTE)hMod, true);
names = (char **)GetPtrFromRVA(ied->AddressOfNames, ntHd, (PBYTE)hMod, true);
ordinals = (unsigned short *)GetPtrFromRVA(ied->AddressOfNameOrdinals, ntHd, (PBYTE)hMod, true);
funcs = (FARPROC *)GetPtrFromRVA(ied->AddressOfFunctions, ntHd, (PBYTE)hMod, true);
unsigned int i;
for(i = 0; i < ied->NumberOfNames; i++)
if(!stricmp((char *)GetPtrFromRVA((DWORD)names[i], ntHd, (PBYTE)hMod, true), func))
break;
if(i >= ied->NumberOfNames)
return NULL;
return MakePtr(FARPROC, hMod, funcs[ordinals[i]]);
}
// Matt Pietrek's function
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned int i;
for ( i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// This 3 line idiocy is because Watcom's linker actually sets the
// Misc.VirtualSize field to 0. (!!! - Retards....!!!)
DWORD size = section->Misc.VirtualSize;
if ( 0 == size )
size = section->SizeOfRawData;
// Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + size)))
return section;
}
return 0;
}
unsigned long GetMappedSectionOffset(IMAGE_NT_HEADERS *ntHd, IMAGE_SECTION_HEADER *seHd, void *base)
{
IMAGE_SECTION_HEADER *section = IMAGE_FIRST_SECTION(ntHd);
unsigned int i;
unsigned long offset = MakeDelta(unsigned long, section, base);
for(i = 0; i < ntHd->FileHeader.NumberOfSections; i++, section++)
{
if(section->Name == seHd->Name)
{
offset = MakeDelta(unsigned long, section->VirtualAddress, section->PointerToRawData);
break;
}
//offset += (section->SizeOfRawData > ntHd->OptionalHeader.SectionAlignment ?
// section->SizeOfRawData - ntHd->OptionalHeader.SectionAlignment :
// ntHd->OptionalHeader.SectionAlignment - section->SizeOfRawData);
}
return offset;
}
// This function is also Pietrek's
LPVOID GetPtrFromRVA( DWORD rva, IMAGE_NT_HEADERS *pNTHeader, PBYTE imageBase, bool mapped )
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT delta;
unsigned long offset = 0;
pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );
if(mapped)
offset = GetMappedSectionOffset(pNTHeader, pSectionHdr, imageBase);
if ( !pSectionHdr )
return 0;
delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
return (PVOID) ( imageBase + rva - delta + offset);
}