MSDN says that OpenProcess() must return either a valid handle, or NULL on error.
However, I met a rare situation on Win7 x64 (and also on Win 8.1 x86, Win XP x64, Win Vista x64) where OpenProcess() returned -1 for the current process, i.e. the pseudo handle, while I enumerated processes. It occurs very rarely from time to time (when I run my test suite on different platforms). And I can't reproduce it on Win 10.
Then CloseHandle() fails on this handle with ERROR_INVALID_HANDLE error. But on the other hand MSDN says that
The pseudo handle need not be closed when it is no longer needed. Calling the CloseHandle function with a pseudo handle has no effect.
Why does this happen? Is it correct behavior for OpenProcess()?
Below is an example of my code:
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: I found why my tests never fail on Win 10 platform - CloseHandle(HANDLE(-1)) always returns TRUE on Win 10, while on Win 7 it returns FALSE with 0x6 error. But I still have no explanation about OpenProcess() behaviour.
SOLUTION: As Ben Voigt said (see the accepted answer) there was a hook in the test environment, which was not cleared after the previous test suite run. After days of debugging the hook was found and localized, the test suite was fixed to clean the hooks up. Now OpenProcess call works correctly.
The most likely explanation is a poorly written
OpenProcesshook, for example both antimalware and malware use such hooks.Writer of this hook didn't read the
OpenProcessdocumentation carefully, and when real WindowsOpenProcesssucceeds but the hook wants to block your access, it is doing(This could be a copy/paste error from also writing a
CreateFilehook)Due to the fact such hooks are predominantly used in rootkits -- both "evil" and "good" (but accidentally evil anyway) varieties, you probably won't be able to confirm the hook from inside the system. A kernel debugger connection, on the other hand, should show that during real Windows OpenProcess execution, the return address is to the hook code, not the kernel transition stub.