为什么OpenProcess给了我一个非现有pid的非NULL HANDLE?

use*_*536 2 c++ winapi

我尽可能地减少代码以保持 代码sscce这段代码的作用:

  • 启动Windows记事本 CreateProcess
  • 暂停.所以Windows有一些时间来初始化记事本
  • TerminateProcess在我们得到的把手上杀了记事本CreateProcess.
  • 等待进程句柄终止,因为TerminateProcess是异步
  • 打电话OpenProcess给死去的pid
  • 玩我的僵尸......

您可以在调试中轻松检查(在OpenProcess之前),在任务管理器或processExplorer中找不到给定的Pid.但没有其他Windows API函数似乎接受这个Pid

#include "stdafx.h"
#include <windows.h>
#include "Psapi.h"
#include <TlHelp32.h>
#include <iostream>
#include <cassert>

typedef unsigned long PID;
typedef const std::string& P_PATH;

// Launch an executable given by a path and set a few infomatives stuffs passed as ref parameters
bool launch_process(P_PATH path, STARTUPINFO& info, PROCESS_INFORMATION& processInfo, HANDLE& hProcess, PID& pid)
{
    setlocale(LC_ALL, "en_US.utf8");
    std::wstring widestr = std::wstring(path.begin(), path.end());
    const wchar_t* widecstr = widestr.c_str();

    LPTSTR szCmdline = _tcsdup(widecstr);

    if (CreateProcess(szCmdline, NULL, NULL, NULL, false, NULL, NULL, NULL, &info, &processInfo))
    {
        hProcess = processInfo.hProcess;
        pid = processInfo.dwProcessId;
        return true;
    }
    return false;
}

int main(int argc, char* argv[])
{
    // Setup
    // -----
    bool OK = false;

    STARTUPINFO info = { sizeof(info) };
    PROCESS_INFORMATION processInfo;
    HANDLE hProcess;
    PID pid = 0;

    // launch notepad
    // --------------
    OK = launch_process("C:\\WINDOWS\\System32\\notepad.exe", info, processInfo, hProcess, pid);
    assert(OK);

    // wait a bit
    // ----------
    system("PAUSE");
    SetLastError(0);

    // get Handle on notepad
    // ---------------------
    hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, false, static_cast<DWORD>(pid));
    std::cout << "Error: " <<  GetLastError() << std::endl;

    // Kill notepad
    // ------------
    UINT exitCode = 0;
    DWORD dwWaitResult = 0;

    SetLastError(0);
    OK = TerminateProcess(hProcess, exitCode);
    std::cout << "Error: " << GetLastError() << std::endl;

    // ensure everything went well ( we need to wait because TerminateProcess is asynchronous )
    if (!OK || (dwWaitResult != WaitForSingleObject(hProcess, INFINITE)))
        return -1;

    // Cleanup
    CloseHandle(hProcess);
    CloseHandle(processInfo.hProcess);
    CloseHandle(processInfo.hThread);
    hProcess = nullptr;
    processInfo.hProcess = nullptr;

    // Ya know what let's reopen the pid I just killed 
    // ( you can see that notepad was started then killed, you can check the pid does not exist in either the task manager or processExplorer )
    SetLastError(0);
    hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, false, static_cast<DWORD>(pid));
    std::cout << "Error: " << GetLastError() << std::endl;

    // Yeah I can speak to the deads! 
    if (hProcess != nullptr)
    {
        LPWSTR szProcessName = L"";
        GetModuleFileNameEx(hProcess, NULL, szProcessName, sizeof szProcessName);

        char c_szText[MAX_PATH];
        wcstombs(c_szText, szProcessName, wcslen(szProcessName) + 1);

        // But the deads have no names
        std::cout << "Error: " << GetLastError() << std::endl;
        std::cout << "Zombie Name: " << c_szText << std::endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*Ben 9

  1. 它没有出现在任务管理器的进程列表中,因为它已终止.任务管理器不显示僵尸(此行为不同于例如ps -Af f显示僵尸的Linux ).

  2. 它仍然存在并且可以访问,OpenProcess因为进程对象尚未被破坏,即它处于僵尸状态.这将是因为另一个进程有一个开放的句柄.例如,

    • 一个防病毒软件,它可以调用OpenProcess来获取信息以评估应用程序是否是恶意的,或者
    • 进程监视器,它获取各种信息,可能是其中一些调用OpenProcess来获取,或者
    • DWM,我想,但不知道,调用OpenProcess来获取有关应用程序是否支持高DPI模式等的信息,或者
    • 任何数量的其他应用程序可能先前已调用OpenProcess并且仍具有仍处于打开状态的句柄.

德:

  • 一旦关闭句柄,不要指望过程对象被销毁,因为你的句柄不是唯一的句柄.

  • 僵尸状态对于进程来说是完全合法的状态.如果它们已经终止,所有进程将处于僵尸状态,并且有人正在等待阅读其退出代码GetExitCodeProcess,或者对进程状态有任何其他兴趣.通常,一旦读取了退出代码,对流程的兴趣就会减弱,句柄会被关闭,最后流程将被销毁.

  • 一旦过程被破坏,PID就可以重复使用.(相反,在关闭所有句柄之前,不能重复使用PID).在Windows中,内核更喜欢低编号的PID,并且会很快重用它们.此行为与Linux不同,后者更喜欢递增PID,并且在达到最大值之前不会重复使用它们.

  • 如果您想要进程的句柄,请不要关闭它.

  • 还应该注意的是,(AFAIK)这些"僵尸"过程对象并不是特别重要的资源.进程地址空间已经被回收,所有句柄都消失了,依此类推 - 剩下的就是一些会计信息. (3认同)