一、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-hant/n/269882.html
微信掃一掃
支付寶掃一掃