一、zwquerysysteminformation的介紹
zwquerysysteminformation是一種Windows系統API函數,用於獲取系統的各種信息,例如進程、線程、堆、模塊、驅動程序等信息。zwquerysysteminformation具有很高的靈活性和可擴展性,可以用於開發各種系統監控、信息管理和分析工具。
二、zwquerysysteminformation的使用方法
使用zwquerysysteminformation需要傳入不同的參數來獲取不同類型的系統信息,下面以獲取所有進程信息為例:
NTSTATUS GetProcessList() { PSYSTEM_PROCESS_INFO pProcessInfo = NULL; PVOID pCurr = NULL; ULONG uRetSize = 0; NTSTATUS Status = ZwQuerySystemInformation(SystemProcessInformation, pProcessInfo, 0, &uRetSize); if (Status == STATUS_INFO_LENGTH_MISMATCH) { pProcessInfo = (PSYSTEM_PROCESS_INFO)ExAllocatePoolWithTag(NonPagedPool, uRetSize, 'Proc'); if (pProcessInfo == NULL) { return STATUS_NO_MEMORY; } Status = ZwQuerySystemInformation(SystemProcessInformation, pProcessInfo, uRetSize, &uRetSize); if (!NT_SUCCESS(Status)) { ExFreePool(pProcessInfo); return Status; } pCurr = pProcessInfo; do { DbgPrint("[%lu] [%S]\n", ((PSYSTEM_PROCESS_INFO)pCurr)->UniqueProcessId, \ ((PSYSTEM_PROCESS_INFO)pCurr)->ImageName.Buffer); pCurr = ((PSYSTEM_PROCESS_INFO)pCurr)->NextEntryOffset + pCurr; } while (((PSYSTEM_PROCESS_INFO)pCurr)->NextEntryOffset); ExFreePool(pProcessInfo); return STATUS_SUCCESS; } return Status; }
首先調用ZwQuerySystemInformation函數獲取所需信息的大小,如果大小不夠,需要重新分配內存並重新調用ZwQuerySystemInformation函數。接著遍歷所有進程信息,輸出進程ID和進程名。
三、zwquerysysteminformation的實現
zwquerysysteminformation的實現需要使用系統調用機制,在編程上需要注意以下幾點:
1.使用雙重調用,第一次獲取所需緩衝區大小,第二次獲取實際數據。
2.遍歷緩衝區的每個節點,根據節點的偏移量可以找到下一個節點,直到遍歷完所有的數據。
3.釋放分配的緩衝區。
下面是ZwQuerySystemInformation的實現代碼:
NTSYSCALLAPI NTSTATUS NTAPI ZwQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL) { ULONG_PTR ServiceTable = (ULONG_PTR)KeServiceDescriptorTable->ServiceTableBase; ULONG_PTR CounterTable = (ULONG_PTR)KeServiceDescriptorTable->CounterTableBase; PULONG ServiceTableBase = (PULONG)(ServiceTable + 4); PULONG CounterTableBase = (PULONG)(CounterTable + 4); PULONG RegistryTableBase = (PULONG)(ServiceTable + 8); ULONG_PTR FunctionAddress = ServiceTableBase[SystemInformationClass]; ULONG_PTR OldServiceDescriptor = 0; KIRQL OldIrql; NTSTATUS Status; __asm { cli mov eax, cr0 push eax and eax, 0xFFFEFFFF mov cr0, eax sti } OldServiceDescriptor = ServiceTableBase[SystemInformationClass]; KeRaiseIrql(HIGH_LEVEL, &OldIrql); ServiceTableBase[SystemInformationClass] = (ULONG)NewSystemCallHandler; Status = ZwQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); ServiceTableBase[SystemInformationClass] = OldServiceDescriptor; KeLowerIrql(OldIrql); __asm { cli mov eax, cr0 pop ecx or eax, ecx mov cr0, eax sti } return Status; }
此處為了演示原理,省略了實現中未使用到的代碼,具體實現還應該考慮安全和效率等因素。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/269882.html