一、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/n/269882.html