NtQuerySystemInformation获取进程/线程状态
__kernel_entry NTSTATUS NtQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
这是一个NT函数,需要通过LoadLibrary()和GetProcAddress()来获取其地址继而调用它。其第一个参数SystemInformationClass指定要检索的系统信息的类型,如果要检测进程和线程的信息就让参数的值为SystemProcessInformation。由SystemInformation参数指向的缓冲区包含每个进程的SYSTEM_PROCESS_INFORMATION结构。这些结构中的每一个紧随其后的是内存中的一个或多个SYSTEM_THREAD_INFORMATION结构,这些结构为上一个进程中的每个线程提供信息。
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER Reserved1[3];
ULONG Reserved2;
PVOID StartAddress; //线程开始的虚拟地址;
CLIENT_ID ClientId; //线程标识符;
KPRIORITY Priority; //线程优先级;
LONG BasePriority; //基本优先级;
ULONG Reserved3;
ULONG ThreadState; //当前状态;
ULONG WaitReason; //等待原因;
} SYSTEM_THREAD_INFORMATION;
ThreadState的值与WaitReason的值都等于5则表示线程被挂起了。如果我们要判断进程的状态就可以通过判断进程中所有线程是不是都被挂起了。
#include <winternl.h>
typedef NTSTATUS(_stdcall * pfnNtQuerySystemInformation)(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
int main()
{
pfnNtQuerySystemInformation NtQuerySystemInformation = (pfnNtQuerySystemInformation)::GetProcAddress(::LoadLibrary(TEXT("ntdll.dll")),TEXT("NtQuerySystemInformation"));
LPVOID dwBufferProcess = 0; //接收数据的缓冲区
DWORD dwBufferProcessSize = 0; //需要接收的数据的缓冲区大小
DWORD dwThreadNum; //进程中所含线程数目
NtQuerySystemInformation(SystemProcessInformation, 0, 0, &dwBufferProcessSize);
dwBufferProcess = new BYTE[dwBufferProcessSize + 0x10000](); //为了防止进程/线程信息发生突变,多申请0x10000内存
LPVOID dwOldBufferProcess = dwBufferProcess; //保存缓冲区地址
NtQuerySystemInformation(SystemProcessInformation, dwBufferProcess, dwBufferProcessSize + 0x10000, &dwBufferProcessSize);
dwThreadNum = ((SYSTEM_PROCESS_INFORMATION*)dwBufferProcess)->NumberOfThreads; //线程数目
while(TRUE)
{
LPVOID dwAddress = dwBufferProcess;
dwStatus = 0;
dwBufferProcess = (BYTE*)dwBufferProcess + sizeof(SYSTEM_PROCESS_INFORMATION);
for (DWORD i = 0; i < dwThreadNum; i++)
{
//检测进程状态和导致此状态的原因
if (((SYSTEM_THREAD_INFORMATION*)dwBufferProcess)->ThreadState == 5 && ((SYSTEM_THREAD_INFORMATION*)dwBufferProcess)->WaitReason == 5)
dwStatus = 0;
else
dwStatus = 1;
dwBufferProcess = (BYTE*)dwBufferProcess + sizeof(SYSTEM_THREAD_INFORMATION); //指向此进程的下一个线程结构
}
dwBufferProcess = ((BYTE*)dwAddress + ((SYSTEM_PROCESS_INFORMATION*)dwAddress)->NextEntryOffset); //指向下一个进程
if (((SYSTEM_PROCESS_INFORMATION*)dwAddress)->NextEntryOffset == 0) //遍历完成结束
break;
}
delete[] dwOldBufferProcess; //释放内存
}
//如果进程对应的dwStatus的值为0则表示进程的所有线程都被挂起了,也就说明进程被挂起了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】