NtQuerySystemInformation
如果SystemInformationLength太小而无法保持信息返回错误STATUS_INFO_LENGTH_MISMATCH
。( RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH)==ERROR_BAD_LENGTH
)
需要了解一些SystemInformationClass返回众所周知的固定大小数据。例如SystemBasicInformation
所以你需要为这个固定大小的信息类做下一步:
SYSTEM_BASIC_INFORMATION sbi;
NTSTATUS status = ZwQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), 0);
if (0 <= status)
{
// do something
}
但一些信息类返回可变长度数据。开始时所需的长度是未知的,STATUS_INFO_LENGTH_MISMATCH
这里是绝对正常错误(不是致命的)。您需要始终在循环中查询的可变长度信息类并检查返回的状态STATUS_INFO_LENGTH_MISMATCH
作为条件继续循环:
do
{
...
status = ZwQuerySystemInformation(...);
...
} while (status == STATUS_INFO_LENGTH_MISMATCH);
为什么在循环中?因为在系统返回给您接收请求的信息所需的缓冲区大小之后以及在您ZwQuerySystemInformation
使用此缓冲区大小再次调用之前,所需的长度可能会发生变化。
一个很好的例子,SystemProcessInformation
它获取了有关当前在系统中运行的所有进程和线程的信息。系统返回给您所需的缓冲区大小后 - 新线程或进程可以在系统中启动 - 结果可能需要更大的缓冲区。
我们可以通过以下方式查询此信息:
NTSTATUS QueryProcessInformation()
{
NTSTATUS status;
ULONG cb = 0x10000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (void* buf = new BYTE[cb])
{
if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
DbgPrint("%p %wZ\n", pspi->UniqueProcessId, &pspi->ImageName);
} while (NextEntryOffset = pspi->NextEntryOffset);
}
delete [] buf;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}
或者我们可以在堆栈中使用累积分配(这仅适用于用户模式,我们有巨大的堆栈大小)
NTSTATUS QueryProcessInformation2()
{
NTSTATUS status;
union {
PVOID buf;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
ULONG cb = 0, rcb = 0x10000;
volatile UCHAR guz;
PVOID stack = alloca(guz);
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = ZwQuerySystemInformation(SystemProcessInformation, buf, cb, &rcb)))
{
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
DbgPrint("%p %wZ\n", pspi->UniqueProcessId, &pspi->ImageName);
} while (NextEntryOffset = pspi->NextEntryOffset);
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
return status;
}