OpenProcess 调用 returns 伪句柄

OpenProcess call returns pseudo handle

MSDN 说 OpenProcess() 必须 return 一个有效的句柄,或者错误时为 NULL。

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

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

The pseudo handle need not be closed when it is no longer needed. Calling the CloseHandle function with a pseudo handle has no effect.

为什么会这样? 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 上总是 returns TRUE,而在 Win 7 上它 return s FALSE 出现 0x6 错误。但我仍然无法解释 OpenProcess() 行为。

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

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

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

return INVALID_HANDLE_VALUE;

(这可能是一个 copy/paste 错误,因为还写了一个 CreateFile 钩子)

由于此类挂钩主要用于 rootkit——"evil" 和 "good" (but accidentally evil anyway) 变种,您可能无法从系统内部确认挂钩。另一方面,内核调试器连接应该表明在真正的 Windows OpenProcess 执行期间,return 地址指向挂钩代码,而不是内核转换存根。