在 Windows 操作系统中,了解正在运行的进程的信息对于系统管理和性能优化至关重要。通过遍历系统进程信息,我们可以获取进程的 ID、名称、线程数、句柄数以及各种性能指标,从而帮助我们了解系统的运行状况并进行必要的调整和优化。本文将详细介绍一种通过调用 Windows 系统API来遍历系统进程信息的技术,同时提供一段用 C++ 编写的示例代码。
操作原理
Windows 操作系统提供了一系列API函数,可以用于获取系统状态和信息。其中之一是 NtQuerySystemInformation 函数,该函数可以用来获取各种系统信息,包括进程信息。通过调用 NtQuerySystemInformation 函数,并将系统信息结构体填充到提供的缓冲区中,我们可以获得系统中运行的所有进程的信息。
在示例代码中,首先定义了一系列结构体,用于存储进程和线程的详细信息。然后通过调用 NtQuerySystemInformation 函数来获取系统进程信息,遍历返回的进程信息结构体,逐个获取每个进程的信息,包括进程名、进程ID、句柄数、线程数等,并在控制台输出。
具体实现
示例代码中使用了以下关键技术:
- 使用 NtQuerySystemInformation 函数获取系统进程信息。
- 遍历返回的进程信息结构体,获取每个进程的详细信息。
- 输出获取到的进程信息到控制台。
示例代码解析
以下是示例代码中用到的关键部分:
- 定义了用于存储进程信息的 _SYSTEM_PROCESS_INFORMATION 结构体和用于存储线程信息的 _SYSTEM_THREAD_INFORMATION 结构体。
- 使用 NtQuerySystemInformation 函数获取系统进程信息,并遍历返回的进程信息结构体,逐个获取每个进程的信息并输出到控制台。
完整代码
#include <iostream>
#include <Windows.h>#ifdef _WIN64
typedef ULONG64 KPRIORITY;
#else
typedef LONG KPRIORITY;
#endif
#define SystemProcessInformation 5 // 功能号#ifdef _M_IX86
typedef struct _CLIENT_ID
{DWORD UniqueProcess;DWORD UniqueThread;
} CLIENT_ID, * PCLIENT_ID;
#endif // x86模式下#ifdef _M_X64
typedef struct _CLIENT_ID
{ULONG64 UniqueProcess;ULONG64 UniqueThread;
} CLIENT_ID, * PCLIENT_ID;
#endif // x64模式下typedef struct _UNICODE_STRING {USHORT Length;USHORT MaximumLength;PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;typedef enum _KWAIT_REASON
{Executive = 0,FreePage = 1,PageIn = 2,PoolAllocation = 3,DelayExecution = 4,Suspended = 5,UserRequest = 6,WrExecutive = 7,WrFreePage = 8,WrPageIn = 9,WrPoolAllocation = 10,WrDelayExecution = 11,WrSuspended = 12,WrUserRequest = 13,WrEventPair = 14,WrQueue = 15,WrLpcReceive = 16,WrLpcReply = 17,WrVirtualMemory = 18,WrPageOut = 19,WrRendezvous = 20,Spare2 = 21,Spare3 = 22,Spare4 = 23,Spare5 = 24,WrCalloutStack = 25,WrKernel = 26,WrResource = 27,WrPushLock = 28,WrMutex = 29,WrQuantumEnd = 30,WrDispatchInt = 31,WrPreempted = 32,WrYieldExecution = 33,WrFastMutex = 34,WrGuardedMutex = 35,WrRundown = 36,MaximumWaitReason = 37
} KWAIT_REASON;// 线程结构体
typedef struct _SYSTEM_THREAD_INFORMATION
{LARGE_INTEGER KernelTime;LARGE_INTEGER UserTime;LARGE_INTEGER CreateTime;ULONG WaitTime;PVOID StartAddress;CLIENT_ID ClientId;KPRIORITY Priority;LONG BasePriority;ULONG ContextSwitches;ULONG ThreadState;KWAIT_REASON WaitReason;
} SYSTEM_THREAD_INFORMATION, * PSYSTEM_THREAD_INFORMATION;// 进程结构体
typedef struct _SYSTEM_PROCESS_INFORMATION
{ULONG NextEntryOffset;ULONG NumberOfThreads;LARGE_INTEGER WorkingSetPrivateSize; // since VISTAULONG HardFaultCount; // since WIN7ULONG NumberOfThreadsHighWatermark; // since WIN7ULONGLONG CycleTime; // since WIN7LARGE_INTEGER CreateTime;LARGE_INTEGER UserTime;LARGE_INTEGER KernelTime;UNICODE_STRING ImageName;KPRIORITY BasePriority;HANDLE UniqueProcessId;HANDLE InheritedFromUniqueProcessId;ULONG HandleCount;ULONG SessionId;ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation)SIZE_T PeakVirtualSize;SIZE_T VirtualSize;ULONG PageFaultCount;SIZE_T PeakWorkingSetSize;SIZE_T WorkingSetSize;SIZE_T QuotaPeakPagedPoolUsage;SIZE_T QuotaPagedPoolUsage;SIZE_T QuotaPeakNonPagedPoolUsage;SIZE_T QuotaNonPagedPoolUsage;SIZE_T PagefileUsage;SIZE_T PeakPagefileUsage;SIZE_T PrivatePageCount;LARGE_INTEGER ReadOperationCount;LARGE_INTEGER WriteOperationCount;LARGE_INTEGER OtherOperationCount;LARGE_INTEGER ReadTransferCount;LARGE_INTEGER WriteTransferCount;LARGE_INTEGER OtherTransferCount;//SYSTEM_THREAD_INFORMATION Threads[1];
} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION;// 定义函数声明
typedef NTSTATUS (WINAPI* __QuerySystemInformation) (UINT systemInformation,PVOID SystemInformation,ULONG SystemInformationLength,PULONG ReturnLength
);BOOL QueryProcessInformationCallAll() {ULONG cbSize = sizeof(SYSTEM_PROCESS_INFORMATION);__QuerySystemInformation NtQuerySystemInformation = NULL;HMODULE hNtDll = GetModuleHandleW(L"ntdll.dll");if (hNtDll == NULL){wprintf(L"LoadLibrary Failed.\n");return FALSE;}NtQuerySystemInformation = (__QuerySystemInformation)GetProcAddress(hNtDll, "NtQuerySystemInformation");PSYSTEM_PROCESS_INFORMATION sysPSIEntry = NULL, sysForwardLinks = NULL;if (NtQuerySystemInformation == NULL) {wprintf(L"GetProcAddress Failed.\n");return FALSE;}// 调用 NtQuerySystemInformation 查询进程信息NTSTATUS status = 0;status = NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &cbSize);if (status == 0xC0000004){sysPSIEntry = (PSYSTEM_PROCESS_INFORMATION)malloc(cbSize);status = NtQuerySystemInformation(SystemProcessInformation, sysPSIEntry, cbSize, &cbSize);if (status)free(sysPSIEntry);}// 拷贝结构体指针副本sysForwardLinks = sysPSIEntry;// 使用指针副本遍历进程信息while (sysForwardLinks->NextEntryOffset != 0){if (sysForwardLinks->ImageName.Buffer != NULL){wprintf(L"进程名:\t%s \t进程ID:%I64u \t句柄总数:%u \t线程总数:%u \n", sysForwardLinks->ImageName.Buffer, (UINT64)sysForwardLinks->UniqueProcessId,sysForwardLinks->HandleCount, sysForwardLinks->NumberOfThreads);// 打印线程信息PSYSTEM_THREAD_INFORMATION threadInfo = NULL;threadInfo = (PSYSTEM_THREAD_INFORMATION)((UINT64)sysForwardLinks + sizeof(SYSTEM_PROCESS_INFORMATION));DWORD curThreadIndex = 1;do {
#ifdef _WIN64wprintf(L"\t线程ID:%I64u \t起始地址:0x%I64X \t线程的状态码:%u\n", threadInfo->ClientId.UniqueThread, (UINT64)threadInfo->StartAddress, threadInfo->ThreadState);
#elsewprintf(L"\t线程ID:%d \t起始地址:0x%I32X \t线程的状态码:%u\n",threadInfo->ClientId.UniqueThread,(UINT)threadInfo->StartAddress,threadInfo->ThreadState);
#endif++threadInfo;} while (curThreadIndex++ < sysForwardLinks->NumberOfThreads);wprintf(L"\n");}// 指针的加减运算的单位是根据所指向数据类型大小的。// 字节指针就是1,所以加减运算没问题。// 这里是结构体指针,所以必须转成数字类型再运算。sysForwardLinks = (PSYSTEM_PROCESS_INFORMATION)((UINT64)sysForwardLinks + sysForwardLinks->NextEntryOffset);}// 释放内存free(sysPSIEntry);sysPSIEntry = NULL;sysForwardLinks = NULL;return TRUE;
}int main()
{setlocale(LC_ALL, ".utf8");// 转换控制台代码页编码为 UTF-8QueryProcessInformationCallAll();return 0;
}
测试结果截图:
总结
通过遍历系统进程信息,我们可以了解系统中运行的各种进程的详细信息,从而更好地进行系统管理和性能优化。本文介绍了一种通过调用 Windows 系统API来获取并遍历系统进程信息的技术,并提供了一段示例代码以帮助读者理解该技术的实现方法。希望本文对于对 Windows 系统进程信息感兴趣的读者有所帮助。
发布于:2024.02.07,更新于:2024.02.07