none
《Windows图形编程》的调用pe文件类接口时出现写入冲突的错误 RRS feed

  • 问题

  • 《Windows图形编程》的pe文件类的实现代码:

     

    #include "StdAfx.h"
    #include "KPEFile.h"
    
    KPEFile::KPEFile(HMODULE hModule)
    {
      m_pModule = (LPBYTE)hModule;
      if (::IsBadReadPtr(m_pModule,sizeof(IMAGE_DOS_HEADER)))
      {
        m_pDosHeader = NULL;
        m_pNTHeader = NULL;
      }
      else
      {
        m_pDosHeader = (PIMAGE_DOS_HEADER)m_pModule;
        if (::IsBadReadPtr(RVA2Ptr(m_pDosHeader->e_lfanew),sizeof(IMAGE_NT_HEADERS)))
        {
          m_pNTHeader = NULL;
        }
        else
           m_pNTHeader = (PIMAGE_NT_HEADERS)RVA2Ptr(m_pDosHeader->e_lfanew);
    
      }
    }
    
    KPEFile::~KPEFile(void)
    {
      
    }
    
    const void* KPEFile::GetDirectory( int id )
    {
      return RVA2Ptr(m_pNTHeader->OptionalHeader.DataDirectory[id].VirtualAddress);
    }
    
    PIMAGE_IMPORT_DESCRIPTOR KPEFile::GetImportDescriptor( LPTSTR pDllName )
    {
       PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)GetDirectory(IMAGE_DIRECTORY_ENTRY_IMPORT);
       if (pImport==NULL)
        return NULL;
    
       while (pImport->FirstThunk)
       {
    
         LPCSTR szDllName = static_cast<LPCSTR>(RVA2Ptr(pImport->Name));
         TCHAR szwszDllName[MAX_PATH];
         ::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,szDllName,-1,szwszDllName,MAX_PATH);
    
         if (_tcsicmp(pDllName,szwszDllName)==0)
         {
         return pImport;
         }
    
         pImport++;
       }
       return NULL;
    }
    
    const unsigned long* KPEFile::GetFunctionPtr( PIMAGE_IMPORT_DESCRIPTOR pImport,LPTSTR pProcName )
    {
       PIMAGE_THUNK_DATA32 pThunk;
       pThunk = (PIMAGE_THUNK_DATA32)RVA2Ptr(pImport->OriginalFirstThunk);
    //   pThunk = (PIMAGE_THUNK_DATA32)RVA2Ptr(pImport->FirstThunk);
       for (int i = 0;pThunk->u1.Function;i++)
       {
         bool match;
         if (pThunk->u1.Ordinal&IMAGE_ORDINAL_FLAG32)
         {
           match = ((pThunk->u1.Ordinal&0xFFFF)==((DWORD)pProcName));
         }
         else
         {
    //       LPCSTR szFunctionName = static_cast<LPCSTR>(RVA2Ptr((unsigned long)pThunk->u1.AddressOfData));
           PIMAGE_IMPORT_BY_NAME pFuncName =static_cast<PIMAGE_IMPORT_BY_NAME>(RVA2Ptr((unsigned long)pThunk->u1.AddressOfData));
           TCHAR szwFunctionName[MAX_PATH];
           ::MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,reinterpret_cast<LPCSTR>(pFuncName->Name),-1,szwFunctionName,MAX_PATH);
           match = ((_tcsicmp(pProcName,szwFunctionName))==0);
         }
    
         if (match)
           return (unsigned long*)RVA2Ptr(pImport->FirstThunk)+i;
    
         pThunk++;
       }
    
       return NULL;
    }
    
    FARPROC KPEFile::SetImportAddress( LPTSTR pDllName,LPTSTR pProcName,FARPROC pNewProc )
    {
      PIMAGE_IMPORT_DESCRIPTOR pImport = GetImportDescriptor(pDllName);
      if (NULL!=pImport)
      {
        const unsigned long* pfn = GetFunctionPtr(pImport,pProcName);
        if(::IsBadReadPtr(pfn,sizeof(DWORD)))
          return NULL;
    
        // 读取原来的地址
        FARPROC oldproc = (FARPROC)*pfn;
        DWORD dwWritten;
    
        BOOL bRet = WriteProcessMemory(GetCurrentProcess(),(void*)pfn,&pNewProc,sizeof(DWORD),&dwWritten);
        return oldproc;
      }
      else
        return NULL;
    }
    
    FARPROC KPEFile::SetExportAddress( LPTSTR pProcName,FARPROC pNewProc )
    {
       PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)GetDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT);
    
       if (NULL==pExport)
        return NULL;
    
       unsigned ord =0;
       if ((unsigned)pProcName<0xFFFF) //ordinal
       {
         ord = (unsigned)pProcName;
       }
       else
       {
         const DWORD* pNames = (const DWORD*)RVA2Ptr(pExport->AddressOfNames);
         const WORD *pOrds = (const WORD*)RVA2Ptr(pExport->AddressOfNameOrdinals);
    
         for (unsigned i =0;i<pExport->AddressOfNames;i++)
         {
          if(_tcsicmp(pProcName,static_cast<TCHAR*>(RVA2Ptr(pNames[i])))==0)
          {
            ord = pExport->Base + pOrds[i];
            break;
          }
         }
       }
    
       if ((ord<pExport->Base)||(ord>pExport->NumberOfFunctions))
        return NULL;
    
       DWORD dwWritten = 0;
       DWORD *pRVA = (DWORD*)RVA2Ptr(pExport->AddressOfFunctions)+ord-pExport->Base;
       DWORD rslt = *pRVA;
       DWORD newRVA = (DWORD)pNewProc-(DWORD)m_pModule;
       WriteProcessMemory(GetCurrentProcess(),pRVA,&newRVA,sizeof(DWORD),&dwWritten);
    
       return (FARPROC)RVA2Ptr(rslt);
    }
    
    

     

    外部调用这个类的接口SetImportAddress的代码:

     

    int WINAPI MyMessageBox(HWND hWnd,LPCTSTR pText,LPCTSTR pCaption,UINT nType)
    {
       TCHAR szText[MAX_PATH];
       TCHAR szCaption[MAX_PATH];
       _tcscat(szText,_T("intercepted"));
       _tcscat(szCaption,_T("intercepted"));
       return ::MessageBox(hWnd,pText,pCaption,nType);
    }
    
    int APIENTRY _tWinMain(HINSTANCE hInstance,
               HINSTANCE hPrevInstance,
               LPTSTR  lpCmdLine,
               int    nCmdShow)
    {
      UNREFERENCED_PARAMETER(hPrevInstance);
      UNREFERENCED_PARAMETER(lpCmdLine);
    
       // TODO: 在此放置代码。
    
      KPEFile pe(hInstance);
      pe.SetImportAddress(_T("user32.dll"),_T("MessageBoxW"),(FARPROC)MyMessageBox);
      ::MessageBox(NULL,_T("Test"),_T("SetImportaddress"),MB_OK);
    
      return 0;
    }
    
    

     

    这个程序要实现的功能是将该进程导入的user32.dll中的MessageBoxW函数动态替换为我编写的MyMessageBox,程序编译环境为 VS C++2005,unicode字符集。经过调试进入 KPEFile::SetImportAddress后能找到MessageBoxW函数的地址,WriteProcessMemory函数的返回值也是正确的,但是运行完::MessageBox(NULL,_T("Test"),_T("SetImportaddress"),MB_OK);这一步后却出现写入冲突,错误图片如下:

         然后打开调用堆栈,没有看到有用的信息。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     


    前无古人,后无来者
    2010年11月13日 13:00

全部回复

  • 您好,

    图片看不到,只看到了X符号。能否再发一次图片,或者把出现的问题描述清楚一些(把错误信息发在上面)。

    谢谢。


    Daoping Liu - MSFT
    2010年11月16日 2:30
    版主