/*
  Get the RVA of a function directly from a module.  This allows 64-bit code to
  work with 32-bit DLLs, and eliminates (or at least reduces) the possibility
  of the function already being hooked.
*/

#include "ansicon.h"

static PIMAGE_DOS_HEADER pDosHeader;


static int export_cmp( const void* a, const void* b )
{
  return strcmp( (LPCSTR)a, MakeVA( LPCSTR, *(const PDWORD)b ) );
}


#ifdef _WIN64
DWORD GetProcRVA( LPCTSTR module, LPCSTR func, int bits )
#else
DWORD GetProcRVA( LPCTSTR module, LPCSTR func )
#endif
{
  HMODULE hMod;
  TCHAR   buf[MAX_PATH];
  UINT	  len;
  PIMAGE_NT_HEADERS	  pNTHeader;
  PIMAGE_EXPORT_DIRECTORY pExportDir;
  PDWORD  fun_table, name_table;
  PWORD   ord_table;
  PDWORD  pFunc;
  DWORD   rva;

#ifdef _WIN64
  if (bits == 32)
    len = GetSystemWow64Directory( buf, MAX_PATH );
  else
#endif
  len = GetSystemDirectory( buf, MAX_PATH );
  buf[len++] = '\\';
  wcscpy( buf + len, module );
  hMod = LoadLibraryEx( buf, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
  if (hMod == NULL)
  {
#ifdef _WIN64
    DEBUGSTR( 1, "Unable to load %u-bit %S (%u)!",
		 bits, module, GetLastError() );
#else
    DEBUGSTR( 1, "Unable to load %S (%u)!", module, GetLastError() );
#endif
    return 0;
  }
  // The handle uses low bits as flags, so strip 'em off.
  pDosHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)hMod & ~0xFFFF);
  pNTHeader  = MakeVA( PIMAGE_NT_HEADERS, pDosHeader->e_lfanew );
#ifdef _WIN64
  if (bits == 32)
    pExportDir	= MakeVA( PIMAGE_EXPORT_DIRECTORY,
		  ((PIMAGE_NT_HEADERS32)pNTHeader)->EXPORTDIR.VirtualAddress );
  else
#endif
  pExportDir = MakeVA( PIMAGE_EXPORT_DIRECTORY,
		       pNTHeader->EXPORTDIR.VirtualAddress );
  fun_table  = MakeVA( PDWORD, pExportDir->AddressOfFunctions );
  name_table = MakeVA( PDWORD, pExportDir->AddressOfNames );
  ord_table  = MakeVA( PWORD,  pExportDir->AddressOfNameOrdinals );

  pFunc = bsearch( func, name_table, pExportDir->NumberOfNames,
		   sizeof(DWORD), export_cmp );
  if (pFunc == NULL)
  {
#ifdef _WIN64
    DEBUGSTR( 1, "Could not find %u-bit %s!", bits, func );
#else
    DEBUGSTR( 1, "Could not find %s!", func );
#endif
    rva = 0;
  }
  else
  {
    rva = fun_table[ord_table[pFunc - name_table]];
  }
  FreeLibrary( hMod );
  return rva;
}