如何在 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 的回答一样,这有一个竞争条件,本质上是不安全的。 @Occultaif (string(process.szExeFile) == string(name))
可以用来代替这个函数。我编辑了迈克尔的答案。【参考方案3】:
有两种基本技术。第一个使用PSAPI; MSDN 有 an example 使用 EnumProcesses
、OpenProcess
、EnumProcessModules
和 GetModuleBaseName
。
另一个使用我更喜欢的 Toolhelp。使用CreateToolhelp32Snapshot
获取进程列表的快照,使用Process32First
和Process32Next
遍历它,提供模块名称和进程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#如何通过进程名称获取指定窗口的句柄,通过该句柄获取该窗口的标题?