NtQuerySystemInformation返回24(ERROR_BAD_LENGTH)

时间:2017-09-08 03:56:23

标签: c winapi nt

这是我的功能:

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)。问题在哪里?

3 个答案:

答案 0 :(得分:1)

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

MSDN说NtQuerySystemInformation

  

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

     

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

因此,请检查DWORD MemorySize是否包含非零大小。

答案 1 :(得分:0)

只需删除

if (NT_SUCCESS(Status)) {

并将其替换为:

if(MemorySize){

答案 2 :(得分:0)

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
}

但是一些Information Class返回可变长度数据。所需的长度在开始时是未知的,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;
}