首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么OpenProcess给我一个不存在pid的非空句柄?

问为什么OpenProcess给我一个不存在pid的非空句柄?
EN

Stack Overflow用户
提问于 2016-02-09 16:22:29
回答 1查看 2.5K关注 0票数 2

我尽可能地减少了代码,以保持斯考斯代码所做的工作:

  • 用CreateProcess启动windows记事本
  • 暂停。所以windows有时间插入记事本
  • 杀死记事本,TerminateProcess在我们从CreateProcess得到的手柄上。
  • 等待进程句柄终止,因为TerminateProcess是异步的
  • 调用死pid上的OpenProcess
  • 和我的僵尸玩..。

在调试时,您可以很容易地(在OpenProcess之前)检查给定的Pid在任务管理器或processExplorer中都找不到。但是其他的windows API函数似乎没有接受这个Pid。

代码语言:javascript
复制
#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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-09 16:58:12

  1. 它没有出现在任务管理器中的进程列表中,因为它已经终止。任务管理器不显示僵尸(这种行为不同于Linux ps -Af f,它确实显示僵尸)。
  2. 它仍然存在,OpenProcess可以访问它,因为process对象还没有被销毁,也就是说它处于僵尸状态。这将是因为另一个进程有一个打开的句柄。例如,
代码语言:javascript
复制
- an antivirus, which may call OpenProcess to get information to assess if the application is malicious, or
- Process Monitor, which gets all sorts of information, probably some of which it calls OpenProcess to get, or 
- the DWM, which I imagine, but do not know, calls OpenProcess to get information on whether the application supports e.g. high DPI mode and so forth, or
- any number of other applications may have called OpenProcess previously and have a still open handle.

​

道德:

  • 不要期望一旦关闭句柄,进程对象就会被销毁,因为您的不是唯一的句柄。
  • 僵尸状态是进程所处的完全合法的状态。如果所有进程已经终止,并且有人在等待使用GetExitCodeProcess读取他们的退出代码,或者对进程的状态有任何其他兴趣,那么所有进程都将处于僵尸状态。通常情况下,一旦退出代码被读取,对进程的兴趣就会减弱,句柄被关闭,最后进程将被销毁。
  • 一旦进程被破坏,PID就可以被重用。(相反,除非关闭所有句柄,否则不能重用PID )。在Windows中,内核更喜欢低编号的PID,并且会很快地重用它们。这种行为不同于Linux,Linux更喜欢增量PID,在达到最大值之前不会重用它们。
  • 如果您想要进程的句柄,不要关闭它。
票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35296996

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档