Windows系统中如何通过NtQuerySystemInformation获取进程线程信息
解决SYSTEM_PROCESS_INFORMATION关联线程结构的遍历问题
你已经成功获取到进程信息缓冲区,接下来只需通过指针偏移和链表遍历,就能提取每个进程对应的SYSTEM_THREAD_INFORMATION结构数组,具体步骤如下:
1. 遍历所有进程条目
SYSTEM_PROCESS_INFORMATION的NextEntryOffset字段记录了下一个进程条目的内存偏移量,以此为依据遍历整个进程链表:
PSYSTEM_PROCESS_INFORMATION pCurrentProcess = p; while (true) { // 处理当前进程的线程信息 // ... // 判断是否到达链表末尾 if (pCurrentProcess->NextEntryOffset == 0) break; // 移动到下一个进程条目 pCurrentProcess = (PSYSTEM_PROCESS_INFORMATION)((BYTE*)pCurrentProcess + pCurrentProcess->NextEntryOffset); }
2. 定位当前进程的线程数组
每个SYSTEM_PROCESS_INFORMATION结构末尾,紧跟该进程的SYSTEM_THREAD_INFORMATION数组,数组长度由ThreadCount字段指定。由于进程名称ImageName是紧跟结构的Unicode字符串,需要先跳过这段内存并处理对齐:
// 计算线程数组起始地址 BYTE* pThreadBase = (BYTE*)pCurrentProcess + sizeof(SYSTEM_PROCESS_INFORMATION); // 按指针大小对齐(32位4字节/64位8字节),避免非法内存访问 pThreadBase += (pCurrentProcess->ImageName.Length + sizeof(PVOID) - 1) & ~(sizeof(PVOID) - 1); PSYSTEM_THREAD_INFORMATION pThreads = (PSYSTEM_THREAD_INFORMATION)pThreadBase;
3. 遍历当前进程的所有线程
拿到线程数组起始地址后,根据ThreadCount遍历每个线程并提取信息:
for (DWORD i = 0; i < pCurrentProcess->ThreadCount; i++) { PSYSTEM_THREAD_INFORMATION pThread = &pThreads[i]; // 访问线程核心字段 cout << " 线程ID: " << pThread->ClientId.UniqueThread << endl; cout << " 优先级: " << pThread->Priority << endl; cout << " 状态: " << pThread->ThreadState << endl; }
完整整合示例
将上述步骤嵌入你已有的代码中,完整的进程+线程遍历逻辑如下:
// 假设已成功获取p指向的进程信息缓冲区 PSYSTEM_PROCESS_INFORMATION pCurrentProcess = p; while (true) { // 转换进程名称为ANSI格式输出 WCHAR* pProcessName = pCurrentProcess->ImageName.Buffer; char szProcessName[256] = {0}; WideCharToMultiByte(CP_ACP, 0, pProcessName, -1, szProcessName, sizeof(szProcessName), NULL, NULL); cout << "进程名称: " << szProcessName << " | 进程ID: " << pCurrentProcess->UniqueProcessId << endl; cout << "线程数量: " << pCurrentProcess->ThreadCount << endl; // 定位线程数组 BYTE* pThreadBase = (BYTE*)pCurrentProcess + sizeof(SYSTEM_PROCESS_INFORMATION); pThreadBase += (pCurrentProcess->ImageName.Length + sizeof(PVOID) - 1) & ~(sizeof(PVOID) - 1); PSYSTEM_THREAD_INFORMATION pThreads = (PSYSTEM_THREAD_INFORMATION)pThreadBase; // 遍历线程 for (DWORD i = 0; i < pCurrentProcess->ThreadCount; i++) { PSYSTEM_THREAD_INFORMATION pThread = &pThreads[i]; cout << " -> 线程ID: " << pThread->ClientId.UniqueThread << " | 优先级: " << pThread->Priority << " | 状态: " << pThread->ThreadState << endl; } cout << "-------------------------" << endl; if (pCurrentProcess->NextEntryOffset == 0) break; pCurrentProcess = (PSYSTEM_PROCESS_INFORMATION)((BYTE*)pCurrentProcess + pCurrentProcess->NextEntryOffset); } // 释放内存 VirtualFree(p, 0, MEM_RELEASE); p = NULL;
关键注意事项
- 内存对齐:Windows内核结构按指针大小对齐,必须做对齐处理,否则会触发内存访问错误。
- 结构兼容性:
NtQuerySystemInformation属于未公开API,不同Windows版本的结构字段可能有细微差异,需在目标系统版本测试。 - 字段参考:
SYSTEM_THREAD_INFORMATION常用字段包括ClientId.UniqueThread(线程ID)、Priority(优先级)、StartAddress(线程起始地址)等,可查看winternl.h定义。
内容的提问来源于stack exchange,提问作者Edward Daemon
相关产品推荐
相关产品推荐

