1

这是我的功能:

PVOID QuerySystemInformation(SYSTEMINFOCLASS SystemEnum) {
        DWORD MemorySize = NULL;
        NTSTATUS Status = NtQuerySystemInformation(SystemEnum, NULL, 0, &MemorySize);
        if (NT_SUCCESS(Status)) {
            PVOID Memory = PVOID(Allocate(MemorySize));
            if (Memory != ERROR) {
                Status = NtQuerySystemInformation(SystemEnum, Memory, MemorySize, &MemorySize);
                if (NT_SUCCESS(Status)) {
                    return Memory;
                }
                Free(Memory);
            }
        }
        return ERROR;
    }

我传递SystemBasicInformation给函数。在第一次调用后NtQuerySystemInformation,我得到一个错误。结果RtlNtStatusToDosError(Status)24 (ERROR_BAD_LENGTH)。哪里有问题?

4

3 回答 3

1

似乎没有问题 - 使用零SystemInformationLength参数的调用会出现错误。

MSDN 说NtQuerySystemInformation

ReturnLength [out, optional] - 第四个参数

指向函数写入请求信息的实际大小的位置的可选指针。如果该大小小于或等于 SystemInformationLength 参数,则该函数将信息复制到 SystemInformation 缓冲区;否则,它返回一个 NTSTATUS 错误代码并在 ReturnLength 中返回接收请求信息所需的缓冲区大小。

所以检查是否DWORD MemorySize包含非零大小。

于 2017-09-08T04:14:52.487 回答
1

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;
}
于 2017-09-08T08:43:10.507 回答
-1

只需删除

if (NT_SUCCESS(Status)) {

并将其替换为:

if(MemorySize){
于 2017-09-08T04:10:28.057 回答