如何在 C++ 中按名称获取进程句柄?

Posted

技术标签:

【中文标题】如何在 C++ 中按名称获取进程句柄?【英文标题】:How can I get a process handle by its name in C++? 【发布时间】:2009-05-14 19:12:29 【问题描述】:

我正在尝试获取 example.exe 的进程句柄,因此我可以在其上调用 TerminateProcess。我怎样才能做到这一点?注意,它没有窗口,所以FindWindow 不起作用。

【问题讨论】:

【参考方案1】:
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>

int main( int, char *[] )

    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == TRUE)
    
        while (Process32Next(snapshot, &entry) == TRUE)
        
            if (stricmp(entry.szExeFile, "target.exe") == 0)
              
                HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);

                // Do stuff..

                CloseHandle(hProcess);
            
        
    

    CloseHandle(snapshot);

    return 0;

另外,如果你想在 OpenProcess 中使用 PROCESS_ALL_ACCESS,你可以试试这个:

#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>

void EnableDebugPriv()

    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;

    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

    LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = luid;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges(hToken, false, &tkp, sizeof(tkp), NULL, NULL);

    CloseHandle(hToken); 


int main( int, char *[] )

    EnableDebugPriv();

    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

    if (Process32First(snapshot, &entry) == TRUE)
    
        while (Process32Next(snapshot, &entry) == TRUE)
        
            if (stricmp(entry.szExeFile, "target.exe") == 0)
              
                HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);

                // Do stuff..

                CloseHandle(hProcess);
            
        
    

    CloseHandle(snapshot);

    return 0;

【讨论】:

您的代码将跳过系统中的第一个进程(但是,第一个进程很可能是“SYSTEM”,因此没有用户可见的错误。) 将其更改为: HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION + PROCESS_VM_READ + PROCESS_TERMINATE, FALSE, entry.th32ProcessID );我会给你答案 我已经能够从这个答案中取得很大进展 - 非常感谢所有做出贡献的人。不过,我遇到了权限问题。即使使用 EnableDebugPriv,当我尝试打开不属于我自己的进程时,“我的 OpenProcess 失败并出现错误 5(访问被拒绝)”。就我而言,我正在寻找所有用户的 iexplore。 优秀的答案!在 Unicode 和 ANSI 编译标志之间切换时,您应该将行 if (stricmp(entry.szExeFile, "target.exe") == 0) 更改为 if (_tcsicmp(entry.szExeFile, _T("target.exe")) == 0) 以保持类型完整性。 对于像我这样喜欢按字母顺序排列标题的人的注意事项 -- windows.h 必须在 tlhelp32.h 之前包含,否则您最终会遇到关于未定义函数的令人困惑的错误(因为定义取决于windows.h)【参考方案2】:

以下代码显示了如何使用 toolhelp 和 OpenProcess 来获取进程的句柄。为简洁起见,删除了错误处理。

HANDLE GetProcessByName(PCSTR name)

    DWORD pid = 0;

    // Create toolhelp snapshot.
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 process;
    ZeroMemory(&process, sizeof(process));
    process.dwSize = sizeof(process);

    // Walkthrough all processes.
    if (Process32First(snapshot, &process))
    
        do
        
            // Compare process.szExeFile based on format of name, i.e., trim file path
            // trim .exe if necessary, etc.
            if (string(process.szExeFile) == string(name))
            
               pid = process.th32ProcessID;
               break;
            
         while (Process32Next(snapshot, &process));
    

    CloseHandle(snapshot);

    if (pid != 0)
    
         return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    

    // Not found


       return NULL;

【讨论】:

您在“if (MatchProcessName(process.szExeFile, name)”条件中忘记了一个括号。 就像 xian 的回答一样,这有一个竞争条件,本质上是不安全的。 @Occulta if (string(process.szExeFile) == string(name)) 可以用来代替这个函数。我编辑了迈克尔的答案。【参考方案3】:

有两种基本技术。第一个使用PSAPI; MSDN 有 an example 使用 EnumProcessesOpenProcessEnumProcessModulesGetModuleBaseName

另一个使用我更喜欢的 Toolhelp。使用CreateToolhelp32Snapshot获取进程列表的快照,使用Process32FirstProcess32Next遍历它,提供模块名称和进程ID,直到找到你想要的,然后调用OpenProcess获取一个处理。

【讨论】:

【参考方案4】:

可以使用以下代码:

DWORD FindProcessId(const std::wstring& processName)

    PROCESSENTRY32 processInfo;
    processInfo.dwSize = sizeof(processInfo);

    HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (processesSnapshot == INVALID_HANDLE_VALUE) 
        return 0;
    

    Process32First(processesSnapshot, &processInfo);
    if (!processName.compare(processInfo.szExeFile))
    
        CloseHandle(processesSnapshot);
        return processInfo.th32ProcessID;
    

    while (Process32Next(processesSnapshot, &processInfo))
    
        if (!processName.compare(processInfo.szExeFile))
        
            CloseHandle(processesSnapshot);
            return processInfo.th32ProcessID;
        
    

    CloseHandle(processesSnapshot);
    return 0;

用法:

auto processId = FindProcessId(L"blabla.exe");

获取句柄应该是显而易见的,只需调用OpenProcess() 或类似名称即可。

【讨论】:

【参考方案5】:

查看:MSDN Article

您可以使用GetModuleName(我认为?)来获取名称并进行检查。

【讨论】:

大多数 GetModuleName、QueryFullProcessImage 名称等都需要句柄,因此没有多大用处。 Toolhelp 确实返回进程名称。【参考方案6】:

OpenProcess函数

来自 MSDN:

要打开另一个本地进程的句柄并获得完全访问权限,您必须启用 SeDebugPrivilege 权限。

【讨论】:

我没有 pID,只有名字。 SeDebugPrivilege 对于像你一样运行的进程绝对不需要。如果您可以通过它的 ACL 访问该进程(通常对您创建的与您的代码具有相同完整性级别的进程进行访问),则不需要 SeDebugPrivilege。来自同一 MSDN 页面:如果调用者启用了 SeDebugPrivilege 权限,则无论安全描述符的内容如何,​​都会授予请求的访问权限。 是的,你需要先通过迭代进程来获取进程ID。【参考方案7】:

如果您不介意使用system(),那么使用system("taskkill /f /im process.exe") 会比这些其他方法容易得多。

【讨论】:

以上是关于如何在 C++ 中按名称获取进程句柄?的主要内容,如果未能解决你的问题,请参考以下文章

C#如何通过进程名称获取指定窗口的句柄,通过该句柄获取该窗口的标题?

如何在C ++中通过其名称获取进程句柄?

C++ 获取进程句柄问题

如何从 win32 进程获取线程句柄列表?

如何使用 Win32 句柄在 C++ 中获取文件名? [复制]

C++ 如何使用 CreateProcess 来处理进程?