views:

109

answers:

3

The following piece of code is causing an exception on a windows vista x64 and i can't figure why.

size_t pBaseAddr;
char *lpszFuncName;
IMAGE_EXPORT_DIRECTORY *pExportDir;
const char **lpszNames;
unsigned int dwIndex;

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

for(dwIndex = 0; dwIndex < pExportDir->NumberOfFunctions; dwIndex++)
{ 
   if(strcmp((char *)(pBaseAddr + lpszNames[dwIndex]), lpszFuncName) == 0)
       return Something;
}

The problem, i think, is on the strcmp() line, specifically on lpszNames[dwIndex]. It works on 32 bits but on 64 it crashes with a access violation. if you want to see the whole code check my previous question

EDIT: since people didn't look at the link i posted on the question I will post the entire code from the original question.

// 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 != IMAGE_DOS_SIGNATURE)
  return NULL;

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

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


// This emulates GetProcAddress.
void *GetFuncAddr( size_t pBaseAddr, char *lpszFuncName ) 
{
 IMAGE_NT_HEADERS       *pNtHeaders;
 IMAGE_DATA_DIRECTORY   *pDataDir;
 IMAGE_EXPORT_DIRECTORY *pExportDir;
 const char      **lpszNames;
 size_t       *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  = ((size_t *)(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(strcmp((char *)(pBaseAddr + lpszNames[dwIndex]), lpszFuncName) == 0)
   return (void*)(pBaseAddr + lpdwFuncs[dwIndex]);
 }

 return NULL;
}

EDIT2: NO, i am NOT using DWORD.

+1  A: 

An access violation means that you're probably trying to dereference a null pointer in the lpszNames array.

lpszNames[dwIndex] is returning a char *, that probably is not pointing to valid data.

Can you verify that lpszNames[dwIndex] does not return null?

Actually, it may not even have to be null, it could just be an address defined as in 'protected' memory.

John Weldon
no, because whenever I tried to run any line of code that has lpszNames[dwIndex] it causes the crash. I added a NULL check and now it's crashing on that line
Jessica
how are you checking for null? lpszNames[dwIndex] == NULL should not cause an access violation?
John Weldon
OK, i managed to verify that is indeed NOT NULL
Jessica
I wasn't I was it was the same line that it's causing the problem (the strcmp)
Jessica
Is it a valid data location though, or is it pointing to protected memory?
John Weldon
That is the big question. I can't print the pointer (%p) because it crashes, i can't print the contents (%s) because it crashes, I can print in hex (%X) but it doesn't really disclose anything
Jessica
What does the debugger tell you ? `<Bad pointer>`, or something that could make sense ?
RaphaelSP
just access violation. i don't have any debugger that i can install on that 64 bit machine
Jessica
The value in hex should show you if it's in low memory.. print the hex value of the 'good' pointers too and see if they're relatively close...
John Weldon
This is as much information as I can get from that machine: Unhandled exception at 0x00000001400011c0 in program.exe: 0xC0000005: Access violation reading location 0xffffffffffffffff.Then at that address you have movzx edx,byte ptr [rax]
Jessica
There are no good pointers. it crashes on the 1st iteration of the for
Jessica
The pointer seem to be OK. 0x64AD5
Jessica
I think is the pBaseAddr. I am getting that by calling LoadLibraryEx("kernel32.dll", NULL, 0);
Jessica
I installed a debugger on the x64 Windows and it's giving me a bad pointer error when I tried to see what's inside
Jessica
A: 
pNtHeaders = ((IMAGE_NT_HEADERS *)((DWORD)pBaseAddr + pDosHeader->e_lfanew));
if(pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
 return NULL;

You are casting a pointer to DWORD. This is not safe on 64-bit systems where a DWORD is half the size of a pointer. I'm not sure if this is the root of your problems, but it's definitely unsafe.

LnxPrgr3
Thanks, but if you read the rest of the comments you'll see that I already corrected this.
Jessica
Oops -- sorry about that ;)
LnxPrgr3
A: 
void GetFuncAddr(HMODULE hBaseAddr, char *pFuncName) 
{
    unsigned int count = 1;
    IMAGE_DOS_HEADER *pDosHeader;
    IMAGE_NT_HEADERS *pNtHeaders;
    IMAGE_OPTIONAL_HEADER *pOptionalHeader;
    IMAGE_DATA_DIRECTORY *pDataDirectory;
    IMAGE_pExpORT_DIRECTORY *pExp;
    ULONG * addrofnames;
    char *funcname;
    ULONG *funcaddr;

    pDosHeader = (IMAGE_DOS_HEADER *)hBaseAddr; 

    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) 
    { 
     return NULL;
    } 

    pNtHeaders = (IMAGE_NT_HEADERS *)(((BYTE *)pDosHeader) + pDosHeader->e_lfanew); 

    if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)
    { 
     return NULL;
    } 

    pOptionalHeader = &pNtHeaders->pOptionalHeader; 
    pDataDirectory = &pOptionalHeader->pDataDirectory[IMAGE_DIRECTORY_ENTRY_pExpORT]; 

    pExp = (IMAGE_pExpORT_DIRECTORY *)((size_t)pDosHeader + pDataDirectory->VirtualAddress); 

    addrofnames = (ULONG *)((BYTE*) hBaseAddr + pExp->addrofnames);
    funcaddr = (ULONG*) ((BYTE*) hBaseAddr + pExp->AddressOfFunctions);

    for(count = 0; count < pExp->NumberOfNames; count++)
    {
     funcname = (char*)((BYTE*) hBaseAddr + addrofnames[count]);  
     if(strcmp(funcname, pFuncName) == 0)
     { 
      return (void*)((BYTE*) hBaseAddr + funcaddr[count]);
     }
    }

    return NULL;
}
Jessica