You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 12:24:24