Windows 進程包含兩大核心部分:
| 技術 | API/DLL | 支援版本 | 遠端支援 | 資訊豐富度 | 複雜度 |
|---|---|---|---|---|---|
| PSAPI | psapi.dll / psapi.h | NT 4.0+ | 否 (僅本機) | 基本 (名稱、PID、模組) | 低 |
| ToolHelp32 | tlhelp32.h / kernel32.dll | Win95/NT 5.0+ | 否 | 豐富 (模組、執行緒、堆積) | 中 |
| WMI (Win32_Process) | wbemcli / System.Management | Win2K+ | 是 (需管理員權限) | 極豐富 (命令列、擁有者、WQL 查詢) | 高 (COM) |
| Native API (NtQuerySystemInformation) | ntdll.dll (非文檔) | 所有 NT | 否 | 最完整 (核心結構直接映射) | 極高 (不穩定) |
#include
#include
#include
#pragma comment(lib, "psapi.lib")
void PrintProcessNameAndID(DWORD processID)
{
char szProcessName[MAX_PATH] = "unknown";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
if (hProcess) {
HMODULE hMod;
DWORD cbNeeded;
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
GetModuleBaseNameA(hProcess, hMod, szProcessName, sizeof(szProcessName));
}
}
printf("%-20s %-8u\n", szProcessName, processID);
if (hProcess) CloseHandle(hProcess);
}
int main()
{
DWORD aProcesses[1024], cbNeeded, cProcesses;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) return 1;
cProcesses = cbNeeded / sizeof(DWORD);
printf("PID Process Name\n");
for (unsigned int i = 0; i < cProcesses; i++)
if (aProcesses[i] != 0) PrintProcessNameAndID(aProcesses[i]);
return 0;
}
關鍵函數:EnumProcesses、OpenProcess、EnumProcessModules、GetModuleBaseName、GetModuleFileNameEx (完整路徑)。
#include
#pragma comment(lib, "kernel32.lib")
void ListProcessModules(DWORD dwPID)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwPID);
if (hSnap == INVALID_HANDLE_VALUE) return;
MODULEENTRY32 me32 = { sizeof(me32) };
if (Module32First(hSnap, &me32)) {
do {
printf(" Module: %-30s Base: 0x%p Size: %u\n",
me32.szModule, me32.modBaseAddr, me32.modBaseSize);
} while (Module32Next(hSnap, &me32));
}
CloseHandle(hSnap);
}
void ListProcessThreads(DWORD dwPID)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
THREADENTRY32 te32 = { sizeof(te32) };
if (Thread32First(hSnap, &te32)) {
do {
if (te32.th32OwnerProcessID == dwPID)
printf(" Thread ID: %u Priority: %d\n", te32.th32ThreadID, te32.tpBasePri);
} while (Thread32Next(hSnap, &te32));
}
CloseHandle(hSnap);
}
#import "wbemdisp.tlb" raw_interfaces_only
using namespace WbemScripting;
void EnumRemoteProcesses(LPCWSTR pszServer, LPCWSTR pszUser, LPCWSTR pszPwd)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
_bstr_t ns = L"\\\\" + _bstr_t(pszServer) + L"\\root\\cimv2";
IWbemLocatorPtr pLoc; pLoc.CreateInstance(CLSID_WbemLocator);
IWbemServicesPtr pSvc; pLoc->ConnectServer(ns, _bstr_t(pszUser), _bstr_t(pszPwd), NULL, 0, NULL, NULL, &pSvc);
CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
IEnumWbemClassObjectPtr pEnum;
pSvc->ExecQuery(_bstr_t("WQL"), _bstr_t("SELECT Name, ProcessId, CommandLine, ExecutablePath FROM Win32_Process"),
WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
IWbemClassObjectPtr pObj; ULONG uRet;
while (pEnum->Next(WBEM_INFINITE, 1, &pObj, &uRet) == S_OK) {
_variant_t vName, vPid, vCmd, vPath;
pObj->Get(L"Name", 0, &vName, NULL, NULL);
pObj->Get(L"ProcessId", 0, &vPid, NULL, NULL);
pObj->Get(L"CommandLine", 0, &vCmd, NULL, NULL);
pObj->Get(L"ExecutablePath", 0, &vPath, NULL, NULL);
wprintf(L"PID: %d Name: %s\n Cmd: %s\n Path: %s\n\n", (int)vPid, (BSTR)vName, (BSTR)vCmd, (BSTR)vPath);
}
CoUninitialize();
}
PSAPI/ToolHelp 無法直接取得命令列參數。解法:
Win32_Process.CommandLine (本機/遠端)。NtQueryInformationProcess + ProcessCommandLineInformation (Win10 1607+)。PEB->ProcessParameters->CommandLine (複雜、風險高)。CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 於 64-bit 進程中執行,或使用 WMI。EnumProcessModulesEx (PSAPI) 支援 LIST_MODULES_64BIT/32BIT 過濾。OpenProcess 需 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ。按需選擇技術:簡單本機列表用 PSAPI;需模組/執行緒細節用 ToolHelp;需命令列、遠端、WQL 查詢用 WMI;極致效能/核心級資訊研究 Native API。實際專案常組合使用:ToolHelp 列舉 PID → PSAPI 取模組路徑 → WMI 補充命令列/擁有者。