现在的位置: 首页 > 综合 > 正文

32位程序在64位系统上调用GetModuleFileNameEx失败

2013年03月01日 ⁄ 综合 ⁄ 共 1939字 ⁄ 字号 评论关闭

转自: http://blog.csdn.net/anycell/archive/2008/12/12/3505864.aspx


前两天遇到同样的问题,特转载。

-------------------------------------------

今天客户打来电话说我们公司的服务器程序在新装的64位Windows 2003上以系统服务方式启动不起来。初步怀疑是我们的32位服务程序哪个地方在64位机上不兼容了。结果忙活了一上午,终于找到了问题所在。程序里有一段代码是用来判断程序是以服务方式启动还是以窗口形式启动:在应用程序初始化时获得父进程的句柄。然后通过句柄获得父进程的执行程序全路径。如果全路径中存在"service.exe"字符串,则程序以服务方式启动。伪代码如下:

  1. HANDLE hParentProc; //Parent proccess handle initialize
  2. BOOL bRet; //Check if we should run it as service
  3. if(GetModuleFileNameEx(hParentProc, NULL, pszPath, MAX_PATH))
  4. {
  5.     if(strstr(pszPath, "services.exe") != NULL)
  6.     {
  7.         bRet = TRUE;        
  8.     }
  9. }

通过调试发现问题出在GetModuleFileNameEx函数上本来它返回的是获取全路径的长度结果在64位机上返回0,pszPath变量并没有取得父进程的全路径。我用GetLastError()查看返回值为error
299——“Only part of a ReadProcessMemory or WriteProcessMemory request was completed.” 。我开始怀疑是因为32位程序调用API处理64位内存地址时出现的问题。

于是我Google了一下,终于找到答案了:
当我们调用GetModuleFileNameEx的API函数时,为了获得指定进程的全路径,它内部需要访问进程的PEB头(process environment block),将PEB中的信息设置到一个叫PROCESS_BASIC_INFORMATION 的结构体中。结构体声明如下

  1. typedef struct _PROCESS_BASIC_INFORMATION {
  2.     NTSTATUS ExitStatus;
  3.     PPEB PebBaseAddress;
  4.     ULONG_PTR AffinityMask;
  5.     KPRIORITY BasePriority;
  6.     ULONG_PTR UniqueProcessId;
  7.     ULONG_PTR InheritedFromUniqueProcessId;
  8. } PROCESS_BASIC_INFORMATION;

其中PEB的地址被设置在PebBaseAddress中。但是64位进程的PEB头地址是保存在64位长度的地址中的(比如上面说道的系统进程Services.exe),而32位进程的PEB头地址只有32位长度。运行在64位系统上32位应用程序是如何将64位的PEB地址转换成32位地址的呢?如果64位PEB地址的高32位为0,则转换不会出现任何问题。但如果高32位也包含地址信息,那么WOW64(Windows
32-bit on Windows 64-bit,windows 64位系统上兼容32位应用程序的技术,作为由32位向64位程序的过渡方案)只是简单的将低32位的PEB地址赋给32位应用程序中的PebBaseAddress变量,当然就会发生错误了!于是Windows就会出发error 299并返回失败。

    如果你的32位应用程序是运行在Windows XP或者以上的操作系统上的,推荐的解决方案是使用GetProccessImageFileName来替代GetModuleFileNameEx来取得进程的全路径,这个函数内部的内部操作不会像GetModuleFileName那样麻烦,只返回一个全路径字符串而已。但是返回的全路径是DOS格式的盘符路径(
/Device/HarddiskVolumeX),因此需要自己再转换一下。

    出了GetModuleFileNameEx之外,还有EnumProcessModule和EnumProcessModuleEx 也会出现这样的问题,都是因为访问64位进程的PEB头的原因。CreateToolHelpSnapshot调用失败原因也与上面的原理类似。
参考:http://winprogger.com/?p=26



抱歉!评论已关闭.