一、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
微信扫一扫
支付宝扫一扫