OpenProcess调用返回伪句柄

时间:2018-03-22 15:53:02

标签: winapi openprocess

MSDN说OpenProcess()必须返回有效的句柄,或者错误时返回NULL。

然而,我在Win7 x64(以及Win 8.1 x86,Win XP x64,Win Vista x64)上遇到了罕见的情况,其中OpenProcess()为当前进程返回-1,即伪句柄,而我枚举过程。它很少偶尔发生(当我在不同的平台上运行我的测试套件时)。我无法在Win 10上重现它。

然后CloseHandle()在此句柄上失败并出现ERROR_INVALID_HANDLE错误。但另一方面,MSDN表示

  

不再需要时,不需要关闭伪句柄。   使用伪句柄调用CloseHandle函数无效。

为什么会这样?这是OpenProcess()的正确行为吗?

以下是我的代码示例:

HANDLE snap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 prEntry = {};
prEntry.dwSize = sizeof (PROCESSENTRY32);
if (Process32First (snap, &prEntry))
{
   do
   {
       if (prEntry.th32ProcessID)
       {
           HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, prEntry.th32ProcessID);
           // <<<< from time to time h is (-1) here when meets the current process
           if (h)
           {
               wchar_t imageFilename[MAX_PATH + 1] = {};
               if (GetProcessImageFileName(hProc, imageFilename, MAX_PATH))
               {
                   // do something
               }
               if (!CloseHandle(h))
               {
                   // CLoseHandle returns FALSE on pseudo handle (at least on Win 7)
                   DWORD err = ::GetLastError();
                   // err == 0x6, i.e. ERROR_INVALID_HANDLE, for the pseudo handle
                   // << create a memory dump here for further analysis
               }
           }
       }
   }
   while (Process32Next (snap, &prEntry));
}

UPD:我发现为什么我的测试在Win 10平台上永远不会失败 - CloseHandle(HANDLE(-1))总是在Win 10上返回TRUE,而在Win 7上它返回FALSE并出现0x6错误。但我仍然没有解释OpenProcess()行为。

解决方案:正如Ben Voigt所说(参见接受的答案),测试环境中有一个钩子,在之前的测试套件运行后没有清除。经过几天的调试,找到并定位了钩子,修复了测试套件以清理钩子。现在OpenProcess调用正常工作。

1 个答案:

答案 0 :(得分:2)

最可能的解释是写得不好的OpenProcess钩子,例如反恶意软件和恶意软件都使用这种钩子。

这个钩子的作者没有仔细阅读OpenProcess文档,当真正的Windows OpenProcess成功但钩子想要阻止你的访问时,它正在做

return INVALID_HANDLE_VALUE;

(这也可能是写CreateFile挂钩的复制/粘贴错误)

由于这样的钩子主要用于rootkit - 这两个&#34; evil&#34;和"good" (but accidentally evil anyway)种类,你可能无法从系统内部确认钩子。另一方面,内核调试器连接应该表明在实际的Windows OpenProcess执行期间,返回地址是钩子代码,而不是内核转换存根。