__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則表示進程的所有線程都被掛起了,也就說明進程被掛起了。