函數存在於NTDLL.DLL動態連結程式庫中。NTDLL.DLL負責ring3與ring0之間的通訊。當使用子系統方式進行系統調用的時候,ntdll.dll和SSDT會配合使用。
關於ZwQuerySystemInformation這個函數可以用來查詢進程資訊、核心資訊、硬體資訊(例如CPU數目)、控制代碼資訊、時間資訊等54個系統資訊。
該函數的原型是
NTSTATUS WINAPI ZwQuerySystemInformation( __in SYSTEM_INFORMATION_CLASSSystemInformationClass, __in_out PVOIDSystemInformation, __in ULONGSystemInformationLength, __out_opt PULONGReturnLength);
至於第一個參數SYSTEM_INFORMATION_CLASS是一個枚舉結構。枚舉了所有的54個系統資訊。該結構在最後將會列舉出來。
一、使用者模式下的ZwQuerySystemInformation
在使用者模式下必須用LoadLibrary與GetProcAddress來擷取該函數地址。
代碼如下,
先聲明一個函數。typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(INSYSTEM_INFORMATION_CLASS,IN OUT PVOID,INULONG,OUTPULONG);載入NTDLL.DLL,擷取函數地址。NTQUERYSYSTEMINFORMATIONZwQuerySystemInformation = NULL;ZwQuerySystemInformation =(NTQUERYSYSTEMINFORMATION)GetProcAddress(ntdll.dll,"ZwQuerySystemInfromation");
舉例:枚舉進程資訊
要想擷取進程資訊,必須使用第二個參數,第二個參數指向一塊記憶體。必須使用參數1中每個系統資訊對應的結構體來將該記憶體進行轉換。
假設我們要枚舉進程資訊,必須使用下列結構,該結構描述了進程名,線程數,指向下一個模組的指標,建立時間等等。結構描述如下:
typedef struct _SYSTEM_PROCESSES { ULONG NextEntryDelta; //構成結構序列的位移量; ULONG ThreadCount; //線程數目; ULONG Reserved1[6]; LARGE_INTEGER CreateTime; //建立時間; LARGE_INTEGER UserTime; //使用者模式(Ring 3)的CPU時間; LARGE_INTEGER KernelTime; //核心模式(Ring 0)的CPU時間; UNICODE_STRING ProcessName; //進程名稱; KPRIORITY BasePriority; //進程優先權; HANDLE ProcessId; //進程標識符; HANDLE InheritedFromProcessId; //父進程的標識符; ULONG HandleCount; //控制代碼數目; ULONG Reserved2[2]; VM_COUNTERS VmCounters; //虛擬儲存空間的結構; IO_COUNTERS IoCounters; //IO計數結構; SYSTEM_THREADS Threads[1]; //進程相關線程的結構數組; }SYSTEM_PROCESSES,*PSYSTEM_PROCESSES;
迴圈程式如下:
PSYSTEM_PROCESSES psp=NULL; //先為參數2設為空白,dwNeedSize擷取儲存該結構體的記憶體大小status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, NULL, 0, &dwNeedSize); //若使用者提供的緩衝區大小不夠,則返回STATUS_INFO_LENGTH_MISMATCH,並返回實際需要的緩衝區大小if ( status ==STATUS_INFO_LENGTH_MISMATCH ) { pBuffer = new BYTE[dwNeedSize]; status =ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, (PVOID)pBuffer,dwNeedSize, NULL); if ( status ==STATUS_SUCCESS ) { psp = (PSYSTEM_PROCESSES)pBuffer; //強制轉換 printf("PID 線程數工作集大小進程名\n"); do { printf("%-4d",psp->ProcessId); printf(" %3d",psp->ThreadCount); printf(" %8dKB",psp->VmCounters.WorkingSetSize/1024); wprintf(L" %s\n",psp->ProcessName.Buffer); psp = (PSYSTEM_PROCESSES)((ULONG)psp +psp->NextEntryDelta ); }while ( psp->NextEntryDelta != 0 );//迴圈遍曆 } delete []pBuffer; pBuffer =NULL; }
二、核心模式下的ZwQuerySystemInformation
核心模式下的ZwQuerySystemInformation的地址的擷取沒有應用程式層那麼麻煩。直接聲明一下該函數即可。詳細參見:http://www.2cto.com/kf/200901/31447.html
NTSYSAPINTSTATUSNTAPI ZwQuerySystemInformation( IN ULONG SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);
直接使用即可:
ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,pBuffer, cbBuffer, NULL);
這是一個C代碼程式,該程式是在ring3層寫的,主要內容是擷取CPU個數,枚舉進程,枚舉核心模組。該代碼是從網上下載的,因為要用到這個函數,所以小小地研究了一下。