Home > Enterprise >  Difference between QueryVirtualMemoryInformation and VirtualQueryEx
Difference between QueryVirtualMemoryInformation and VirtualQueryEx

Time:12-07

While looking for ways to query specific information about a range of pages in windows I came across two solutions that were used commonly. However these two alternatives seem to return overlapping information.

VirtualQueryEx

Found on MSDN we see that it takes the parameters hProcess, lpAddress, lpBuffer and dwLength to query information for that range of pages. It returns this struct which tells us something about page state, protection and type. Oh well, so a good choice for querying page information right? But wait there is more!

QueryVirtualMemoryInformation

Also found on MSDN and does nearly the same thing. The difference is that it uses a DUMMYSTRUCTNAME and returns a memory structure that overlaps quite perfectly with the struct returned by VirtualQueryEx.

It seems like this could be an oversight and it doesn't matter which one to use. Maybe MS themselves don't even know why there are two overlapping variants inside a single OS. But for someone that does know: What's the difference here?

CodePudding user response:

VirtualQuery and VirtualQueryEx have existed since forever (NT v3.51).

QueryVirtualMemoryInformation is much newer (10 1607) and adds the information class parameter often seen in the NT API. This allows for future expansion. There is currently only one documented class value and the returned information is pretty similar to VirtualQueryEx but not exactly the same (BaseAddress, CommitSize etc).

DUMMYSTRUCTNAME is a compiler thing related to members without a name and has nothing to do with the actual data returned.

CodePudding user response:

exist next NT api - NtQueryVirtualMemory

__kernel_entry NTSYSCALLAPI NTSTATUS NtQueryVirtualMemory(
  [in]            HANDLE                   ProcessHandle,
  [in, optional]  PVOID                    BaseAddress,
  [in]            MEMORY_INFORMATION_CLASS MemoryInformationClass,
  [out]           PVOID                    MemoryInformation,
  [in]            SIZE_T                   MemoryInformationLength,
  [out, optional] PSIZE_T                  ReturnLength
);

where MEMORY_INFORMATION_CLASS can have next values:

enum MEMORY_INFORMATION_CLASS
{
    MemoryBasicInformation, // MEMORY_BASIC_INFORMATION
    MemoryWorkingSetInformation, // MEMORY_WORKING_SET_INFORMATION
    MemoryMappedFilenameInformation, // UNICODE_STRING
    MemoryRegionInformation, // MEMORY_REGION_INFORMATION
    MemoryWorkingSetExInformation, // MEMORY_WORKING_SET_EX_INFORMATION // since VISTA
    MemorySharedCommitInformation, // MEMORY_SHARED_COMMIT_INFORMATION // since WIN8
    MemoryImageInformation, // MEMORY_IMAGE_INFORMATION
    MemoryRegionInformationEx, // MEMORY_REGION_INFORMATION
    MemoryPrivilegedBasicInformation,
    MemoryEnclaveImageInformation, // MEMORY_ENCLAVE_IMAGE_INFORMATION // since REDSTONE3
    MemoryBasicInformationCapped, // 10
    MemoryPhysicalContiguityInformation, // MEMORY_PHYSICAL_CONTIGUITY_INFORMATION // since 20H1
    MemoryBadInformation, // since WIN11
    MemoryBadInformationAllProcesses, // since 22H1
    MaxMemoryInfoClass
} ;

both VirtualQueryEx and QueryVirtualMemoryInformation is thin shell over NtQueryVirtualMemory.

the VirtualQueryEx call NtQueryVirtualMemory with MemoryInformationClass = MemoryBasicInformation

SIZE_T
WINAPI
VirtualQueryEx(
               _In_ HANDLE hProcess,
               _In_opt_ LPCVOID VirtualAddress,
               _Out_writes_bytes_to_(dwLength,return) PMEMORY_BASIC_INFORMATION lpBuffer,
               _In_ SIZE_T dwLength
               )
{
    NTSTATUS status = NtQueryVirtualMemory(hProcess, VirtualAddress, MemoryBasicInformation, dwLength, &dwLength);

    if (0 > status)
    {
        RtlNtStatusToDosError(status);
        return 0;
    }

    return dwLength;
}

the QueryVirtualMemoryInformation call NtQueryVirtualMemory with MemoryInformationClass = MemoryRegionInformationEx. despite MemoryInformationClass parameter still exist, it accept only single value.

BOOL
WINAPI
QueryVirtualMemoryInformation(
                              _In_ HANDLE Process,
                              _In_ const VOID* VirtualAddress,
                              _In_ WIN32_MEMORY_INFORMATION_CLASS MemoryInformationClass,
                              _Out_writes_bytes_(MemoryInformationSize) PVOID MemoryInformation,
                              _In_ SIZE_T MemoryInformationSize,
                              _Out_opt_ PSIZE_T ReturnSize
                              )
{
    NTSTATUS status = MemoryRegionInfo != MemoryInformationClass ? STATUS_INVALID_INFO_CLASS :
        NtQueryVirtualMemory(hProcess, VirtualAddress, MemoryRegionInformationEx, MemoryInformationSize, ReturnSize);

    if (0 > status)
    {
        RtlNtStatusToDosError(status);
        return FALSE;
    }

    return TRUE;
}

so because in both case the same NT api called internal - this 2 win32 api very similar.

  • Related