在Windows x64上访问char **的内容会导致异常

时间:2009-11-20 15:17:40

标签: c windows pointers

以下代码在Windows Vista x64上导致异常,我无法理解原因。

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;
}

我认为问题在于strcmp()行,特别是在lpszNames [dwIndex]上。它工作在32位,但在64位它崩溃与访问冲突。 如果你想看到整个代码check my previous 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:不,我不是在使用DWORD。

3 个答案:

答案 0 :(得分:1)

访问冲突意味着您可能尝试取消引用lpszNames数组中的空指针。

lpszNames[dwIndex]正在返回char *,可能并未指向有效数据。

您能否验证lpszNames[dwIndex]不返回null?

实际上,它甚至可能不必为空,它可能只是一个在“受保护”内存中定义的地址。

答案 1 :(得分:0)

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

您正在投射指向DWORD的指针。这在64位系统上是不安全的,其中DWORD是指针大小的一半。我不确定这是否是你问题的根源,但它绝对不安全。

答案 2 :(得分:0)

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;
}