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.