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则表示进程的所有线程都被挂起了,也就说明进程被挂起了。
原文地址:https://www.cnblogs.com/revercc/p/14064418.html