tags:

views:

159

answers:

2

I was experimenting with the following code to simulate GetProcAddress.

// Retrieve NT header from base address.
IMAGE_NT_HEADERS *GetNtHeaderFromBase( void *pBaseAddr )
{
 IMAGE_DOS_HEADER       *pDosHeader;
 IMAGE_NT_HEADERS       *pNtHeaders;

 pDosHeader = ((IMAGE_DOS_HEADER *)pBaseAddr);
 if(pDosHeader->e_magic != 0x5A4D)
  return NULL;

 pNtHeaders = ((IMAGE_NT_HEADERS *)((DWORD)pBaseAddr + pDosHeader->e_lfanew));
 if(pNtHeaders->Signature != 0x4550)
  return NULL;

 return ((pNtHeaders == NULL) ? NULL : pNtHeaders);
}


// This emulates GetProcAddress.
void *GetFuncAddr( DWORD pBaseAddr, char *lpszFuncName ) 
{
 IMAGE_NT_HEADERS       *pNtHeaders;
 IMAGE_DATA_DIRECTORY   *pDataDir;
 IMAGE_EXPORT_DIRECTORY *pExportDir;
 const char      **lpszNames;
 DWORD       *lpdwFuncs, dwIndex;

 pNtHeaders = GetNtHeaderFromBase((void *)pBaseAddr);
 if(pNtHeaders == NULL)
  return NULL;

 pDataDir = ((IMAGE_DATA_DIRECTORY *)(pNtHeaders->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT));
 if(pDataDir == NULL)
  return NULL;

 pExportDir = ((IMAGE_EXPORT_DIRECTORY *)(pBaseAddr + pDataDir->VirtualAddress));
 if(pExportDir == NULL)
  return NULL;

 lpdwFuncs  = ((DWORD *)(pBaseAddr + pExportDir->AddressOfFunctions));
 lpszNames  = ((const char **)(pBaseAddr + pExportDir->AddressOfNames));
 if(lpdwFuncs == NULL || lpszNames == NULL)
  return NULL;

 for(dwIndex = 0; dwIndex < pExportDir->NumberOfFunctions; dwIndex++)
 { 
  // decrypt funcname and get the address
  if(!cmpstr(((char *)(pBaseAddr + lpszNames[dwIndex])), lpszFuncName))
   return (void*)(pBaseAddr + lpdwFuncs[dwIndex]);
 }

 return NULL;
}

But when I run the program on a Windows Vista x64 I get an access violation. I thought it was the numbers on GetNtHeaderFromBase (the numbers passed on IMAGE_DOS_HEADER and IMAGE_NET_HEADER) but i can't find any reference anywhere as to what it might be on a x64 bit binary.

Anyone has any idea what changes do I need to make to this code to make it work under 64 bit Windows? Or, a better way to achieve a getprocaddress-like function that works on both x32 and x64?

Thank you for the help and the code.

jess.

+3  A: 

I'm not sure if it's your only problem, but DWORD is 32 bits, even on 64-bit platforms. You're casting pointers to this, and on 64 bit that results in truncation. If you want a pointer-sized integer you should use DWORD_PTR or ULONG_PTR.

I would also check that your structures are 64-bit safe in that regard.

asveikau
Could you post an example? After setting DWORD as size_T I'm still crashing on or after: lpszNames = ((const char **)(pBaseAddr + pExportDir->AddressOfNames));
Jessica
As I say, I'm not sure if it's the only problem. Are your structures coming from Microsoft headers or are you declaring them yourself? if the latter, check those. Also, it might help to look at the binary in a hex editor and see if there are any differences with your assumptions.
asveikau
The structs are all declare in winnt.h so they are from Microsoft headers
Jessica
Actually the function cmpstr() inside the for is calling strcmp and on 64bit that is causing the crash i don't know why
Jessica
+2  A: 

The reason why is that you're storing a pointer sized value in a DWORD for the pBaseAddr method. Pointer values are 8 bytes on 64 bit windows while a DWORD is only 4 bytes. You need to do one of the following

  1. Pass pBaseAddr as a pointer (preferred approach)
  2. Pass it as a size_t which will correctly be 4 bytes on 32 bit windows and 8 bytes on 64 bit windows.
JaredPar
Thank you but still crashing either in this line of immediately after: lpszNames = ((const char **)(pBaseAddr + pExportDir->AddressOfNames));
Jessica