Home > Enterprise >  NtQuerySystemInformation SystemHandleInformation wont give correct return size
NtQuerySystemInformation SystemHandleInformation wont give correct return size

Time:08-22

    PSYSTEM_HANDLE_INFORMATION HandleInfo = NULL;
    ULONG HandleInfoLength = 0;
    
    ...
    
    result = NTQSI((SYSTEM_INFORMATION_CLASS)0x10, NULL, 0, &HandleInfoLength);
    if (result != 0xC0000004) {
        printf("OmmeSearchProcessHandle - NTQSI output is unexpected! Expexted : 0xC0000004 Result : 0x%x\n", result);
        return NULL;
    }

    printf("system handle info length : %i\n", HandleInfoLength);
    SIZE_T HandleInfoRegionSize = HandleInfoLength;
    result = NTAVM((HANDLE)(-1), (PVOID*)&HandleInfo, 0, &HandleInfoRegionSize, MEM_COMMIT, PAGE_READWRITE);
    if (!NT_SUCCESS(result)) {
        printf("OmmeSearchProcessHandle - NTAVM failed with result : %x\n", result);
        return NULL;
    }

    result = NTQSI((SYSTEM_INFORMATION_CLASS)0x10, (PVOID)HandleInfo, HandleInfoLength, &HandleInfoLength);
    if (!NT_SUCCESS(result)) {
        printf("OmmeSearchProcessHandle - NTQSI failed with result : %x\n", result);
        printf("system handle info length : %i\n", HandleInfoLength);
        return NULL;
    }

The code above produces this. Somehow the first NtQuerySystemInformation call doesnt give the correct return size, anyone have any idea about this? And then, i stubled upon this on Github, NtQuerySystemInformation won't give us the correct buffer size, is this a common knowledge that NTQSI SystemHandleInformation wont give the correct return size?

CodePudding user response:

the handle count in system is very volatile. so between 2 calls to NtQuerySystemInformation handle count in system can incremented and require more size. you need call NtQuerySystemInformation in loop. and need use SystemExtendedHandleInformation instead SystemHandleInformation

NTSTATUS TestHandles()
{
    NTSTATUS status;
    ULONG cb = 0x400000;
    do 
    {
        union {
            PVOID buf;
            PSYSTEM_HANDLE_INFORMATION_EX pshie;
        };

        status = STATUS_NO_MEMORY;

        if (buf = LocalAlloc(0, cb  = 0x1000))
        {
            if (0 <= (status = NtQuerySystemInformation(SystemExtendedHandleInformation, buf, cb, &cb)))
            {
                if (ULONG_PTR NumberOfHandles = pshie->NumberOfHandles)
                {

                    PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Entry = pshie->Handles;
                    do 
                    {

                    } while (Entry  , --NumberOfHandles);

                }
            }

            LocalFree(buf);
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}

CodePudding user response:

The ReturnLength value returned by a call to NtQuerySystemInformation with SystemHandleInformation does not necessarily represent the required buffer size to hold the entire system handle information - or more precisely, it depends on the input buffer size if it does or not (refer to this). Calling the function twice like in your example is not a good practice even if it returned the expected buffer size, because the required size could change in between your first and second call. A working example could look like this:

void GetHandleInfo()
{
    PSYSTEM_HANDLE_INFORMATION handleInfo = NULL;
    DWORD size = 0, required = 0;
    NTSTATUS handleInfoStatus;

    do 
    {
        if (handleInfo)
        {
            fpExFreePool(handleInfo);
            handleInfo = NULL;
        }

        size = required   PAGE_SIZE;

        if(!(handleInfo = fpExAllocatePool(NonPagedPool, size)))
            goto Done;

    } while ((handleInfoStatus = fpZwQuerySystemInformation(0x10, handleInfo, size, &required)) == STATUS_INFO_LENGTH_MISMATCH);

    if (!NT_SUCCESS(handleInfoStatus))
        goto Done;

    //The handle info is available here

Done:

    if (handleInfo)
        fpExFreePool(handleInfo);

    return;
}
  • Related