如何用C++枚举Windows系统所有用户的全部进程?
你当前的代码无法枚举其他用户进程的核心原因有两个:
- 默认运行的程序没有启用SeDebugPrivilege调试特权,无法跨用户获取其他安全上下文进程的句柄
- OpenProcess请求了
PROCESS_VM_READ权限,该权限需要很高的访问等级,普通上下文无法对系统/其他用户进程获取该权限,导致后续EnumProcessModules调用失败,返回未知进程名。
具体解决步骤
步骤1:为当前进程启用SeDebugPrivilege特权
在进程启动后、枚举进程前,调用以下代码调整令牌权限:
BOOL EnableDebugPrivilege() { HANDLE hToken; TOKEN_PRIVILEGES tp; LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { return FALSE; } if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { CloseHandle(hToken); return FALSE; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { CloseHandle(hToken); return FALSE; } CloseHandle(hToken); return GetLastError() == ERROR_SUCCESS; }
注意:该操作需要程序以管理员身份运行才能成功,普通用户账户没有SeDebugPrivilege的分配权限
步骤2:优化OpenProcess权限与进程名获取逻辑
替换原有的高权限请求与EnumProcessModules逻辑,改用低权限即可调用的API获取进程名:
void PrintProcessNameAndID(DWORD processID) { TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>"); // 改用低权限的PROCESS_QUERY_LIMITED_INFORMATION,Vista及以上系统支持 HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processID); if (NULL != hProcess) { DWORD size = MAX_PATH; // 不需要读进程内存,直接调用API获取进程路径 if (QueryFullProcessImageName(hProcess, 0, szProcessName, &size)) { // 可选:只保留文件名,去掉路径前缀 TCHAR* pName = _tcsrchr(szProcessName, '\\'); if (pName) { _tcscpy_s(szProcessName, MAX_PATH, pName + 1); } } CloseHandle(hProcess); } _tprintf(TEXT("%s (PID: %u)\n"), szProcessName, processID); }
步骤3:修改main函数,启动时先调用权限调整
在main函数最开头加入权限启用逻辑:
int main(void) { // 先启用调试特权 if (!EnableDebugPrivilege()) { _tprintf(TEXT("警告:无法启用调试特权,可能无法枚举全部进程,请尝试以管理员身份运行\n")); } DWORD aProcesses[1024], cbNeeded, cProcesses; unsigned int i; if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) { return 1; } cProcesses = cbNeeded / sizeof(DWORD); for (i = 0; i < cProcesses; i++) { if (aProcesses[i] != 0) { PrintProcessNameAndID(aProcesses[i]); } } return 0; }
备选方案:使用Toolhelp32 API
如果你需要兼容更老的系统,也可以直接改用Toolhelp32系列API枚举进程,对权限要求更低,不需要额外调用OpenProcess即可获取进程名:
#include <tlhelp32.h> void EnumProcessWithToolhelp() { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { return; } PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(hSnapshot, &pe32)) { CloseHandle(hSnapshot); return; } do { _tprintf(TEXT("%s (PID: %u)\n"), pe32.szExeFile, pe32.th32ProcessID); } while (Process32Next(hSnapshot, &pe32)); CloseHandle(hSnapshot); }
内容的提问来源于stack exchange,提问作者mrRobot
相关产品推荐
相关产品推荐

