NtQueryVirtualMemory
Liefert Informationen über Seiten im virtuellen Adressraum eines Zielprozesses.
Prototyp
NTSTATUS NtQueryVirtualMemory( HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, SIZE_T MemoryInformationLength, PSIZE_T ReturnLength );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle auf den abgefragten Prozess. Erfordert PROCESS_QUERY_INFORMATION. |
| BaseAddress | PVOID | in | Adresse innerhalb der abzufragenden Region. Muss nicht seitengerichtet sein. |
| MemoryInformationClass | MEMORY_INFORMATION_CLASS | in | Informationsklasse (MemoryBasicInformation, MemoryMappedFilenameInformation, MemoryRegionInformation, MemoryWorkingSetExInformation, ...). |
| MemoryInformation | PVOID | out | Vom Aufrufer allokierter Puffer für die zurückgegebene Struktur. |
| MemoryInformationLength | SIZE_T | in | Größe des Ausgabepuffers in Bytes. |
| ReturnLength | PSIZE_T | out | Optional. Erhält die Anzahl geschriebener oder benötigter Bytes. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x23 | win10-1507 |
| Win10 1607 | 0x23 | win10-1607 |
| Win10 1703 | 0x23 | win10-1703 |
| Win10 1709 | 0x23 | win10-1709 |
| Win10 1803 | 0x23 | win10-1803 |
| Win10 1809 | 0x23 | win10-1809 |
| Win10 1903 | 0x23 | win10-1903 |
| Win10 1909 | 0x23 | win10-1909 |
| Win10 2004 | 0x23 | win10-2004 |
| Win10 20H2 | 0x23 | win10-20h2 |
| Win10 21H1 | 0x23 | win10-21h1 |
| Win10 21H2 | 0x23 | win10-21h2 |
| Win10 22H2 | 0x23 | win10-22h2 |
| Win11 21H2 | 0x23 | win11-21h2 |
| Win11 22H2 | 0x23 | win11-22h2 |
| Win11 23H2 | 0x23 | win11-23h2 |
| Win11 24H2 | 0x23 | win11-24h2 |
| Server 2016 | 0x23 | winserver-2016 |
| Server 2019 | 0x23 | winserver-2019 |
| Server 2022 | 0x23 | winserver-2022 |
| Server 2025 | 0x23 | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 23 00 00 00 mov eax, 0x23 F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Undokumentierte Hinweise
NtQueryVirtualMemory behält SSN `0x23` über alle Windows-10-/11-/Server-Builds. Es ist die Kernel-Seite von VirtualQuery / VirtualQueryEx, exponiert aber eine deutlich reichere Informationsfläche: MemoryBasicInformation (Zustand, Typ, Schutz), MemoryMappedFilenameInformation (das hinterlegende Image / die Datei als NT-Pfad), MemoryRegionInformation (vollständige VAD-Subtree-Info ab Win10 1803), MemoryImageInformation, MemoryWorkingSetExInformation (Bits pro Seite gültig / locked / shared / shareable). Jede Klasse mappt auf einen eigenen MmQueryVirtualMemory-Branch.
Häufige Malware-Nutzung
Aufklärungs-Klassiker. Den Adressraum enumerieren, um (a) das AMSI-/ETWTI-Mapping im Host-Prozess vor dem Patchen zu lokalisieren, (b) saubere PE-Header in ntdll/kernel32 für `Perun's Fart`-artiges Fresh-Copy-Unhooking zu finden, (c) einen Remote-Prozess auf RWX- oder kürzlich allokierte RW-Regionen abzusuchen, (d) zu bestätigen, dass die Section eines manuell gemappten Image nicht von einem EDR ungemappt wurde. MemoryMappedFilenameInformation erlaubt zudem, im Host geladene EDR-DLLs zu identifizieren, ohne die PEB-Loader-Liste anzufassen.
Erkennungsmöglichkeiten
Hohe Aufrufraten sind normal — Debugger, Profiler und sogar Defender selbst durchlaufen Adressräume permanent. Interessante Telemetrie: Cross-Process-Queries (ProcessHandle != aktuell) aus nicht-instrumentalen Binaries, besonders gefolgt von NtProtectVirtualMemory oder NtWriteVirtualMemory auf dasselbe Ziel innerhalb von Millisekunden. Der ETW-Threat-Intelligence-Provider (`Microsoft-Windows-Threat-Intelligence`) emittiert ProtectVirtualMemory- und AllocVirtualMemory-Events für Cross-Process-Aktionen; Query-dann-Write zu korrelieren ist eine starke Injection-Heuristik.
Direkte Syscall-Beispiele
asmx64 direct stub
; Direct syscall stub for NtQueryVirtualMemory (SSN 0x23, all builds)
NtQueryVirtualMemory PROC
mov r10, rcx ; syscall convention
mov eax, 23h ; SSN
syscall
ret
NtQueryVirtualMemory ENDPcAMSI mapping locator
// Walk the host VA space and locate amsi.dll's image mapping using
// MemoryMappedFilenameInformation -> AmsiScanBuffer can then be patched.
#include <windows.h>
#define MemoryMappedFilenameInformation 2
typedef NTSTATUS (NTAPI *pNtQueryVirtualMemory)(
HANDLE, PVOID, ULONG, PVOID, SIZE_T, PSIZE_T);
PVOID FindAmsi(void) {
pNtQueryVirtualMemory NtQueryVirtualMemory =
(pNtQueryVirtualMemory)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtQueryVirtualMemory");
BYTE buf[1024];
SIZE_T ret;
for (ULONG_PTR addr = 0x10000; addr < 0x7FFFFFFFFFFF; addr += 0x10000) {
if (NtQueryVirtualMemory((HANDLE)-1, (PVOID)addr,
MemoryMappedFilenameInformation, buf, sizeof buf, &ret) == 0) {
UNICODE_STRING *us = (UNICODE_STRING*)buf;
if (wcsstr(us->Buffer, L"\\amsi.dll"))
return (PVOID)addr;
}
}
return NULL;
}rustMEMORY_BASIC_INFORMATION sweep
// Cargo: windows-sys = "0.59" (Win32_System_Memory, Win32_Foundation)
use windows_sys::Win32::System::Memory::*;
use windows_sys::Win32::Foundation::HANDLE;
// Find RWX regions in a remote process — implant validation, EDR audit, or victim recon.
pub unsafe fn find_rwx(proc_handle: HANDLE) -> Vec<usize> {
let mut out = Vec::new();
let mut addr: usize = 0;
let mut mbi: MEMORY_BASIC_INFORMATION = core::mem::zeroed();
while VirtualQueryEx(proc_handle, addr as _, &mut mbi,
core::mem::size_of_val(&mbi)) != 0 {
if mbi.State == MEM_COMMIT && mbi.Protect == PAGE_EXECUTE_READWRITE {
out.push(mbi.BaseAddress as usize);
}
addr = mbi.BaseAddress as usize + mbi.RegionSize;
}
out
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20