> Windows Syscalls
ntoskrnl.exeT1055T1055.002T1055.012

NtWriteVirtualMemory

Writes a buffer from the caller into the virtual address space of a target process.

Prototype

NTSTATUS NtWriteVirtualMemory(
  HANDLE  ProcessHandle,
  PVOID   BaseAddress,
  PVOID   Buffer,
  SIZE_T  NumberOfBytesToWrite,
  PSIZE_T NumberOfBytesWritten
);

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle to the target process with PROCESS_VM_WRITE | PROCESS_VM_OPERATION rights.
BaseAddressPVOIDinDestination virtual address in the target process.
BufferPVOIDinPointer to the source buffer in the caller's address space.
NumberOfBytesToWriteSIZE_TinNumber of bytes to copy from Buffer to BaseAddress.
NumberOfBytesWrittenPSIZE_ToutOptional. Receives the number of bytes actually written. May be NULL.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x3Awin10-1507
Win10 16070x3Awin10-1607
Win10 17030x3Awin10-1703
Win10 17090x3Awin10-1709
Win10 18030x3Awin10-1803
Win10 18090x3Awin10-1809
Win10 19030x3Awin10-1903
Win10 19090x3Awin10-1909
Win10 20040x3Awin10-2004
Win10 20H20x3Awin10-20h2
Win10 21H10x3Awin10-21h1
Win10 21H20x3Awin10-21h2
Win10 22H20x3Awin10-22h2
Win11 21H20x3Awin11-21h2
Win11 22H20x3Awin11-22h2
Win11 23H20x3Awin11-23h2
Win11 24H20x3Awin11-24h2
Server 20160x3Awinserver-2016
Server 20190x3Awinserver-2019
Server 20220x3Awinserver-2022
Server 20250x3Awinserver-2025

Kernel module

ntoskrnl.exeNtWriteVirtualMemory

Related APIs

WriteProcessMemoryNtReadVirtualMemoryNtAllocateVirtualMemoryNtProtectVirtualMemoryZwWriteVirtualMemory

Syscall stub

4C 8B D1            mov r10, rcx
B8 3A 00 00 00      mov eax, 0x3A
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

Undocumented notes

Implemented by `MmCopyVirtualMemory` inside ntoskrnl.exe with `PreviousMode = UserMode`, which forces full probe-and-lock of both buffers. The SSN `0x3A` has been unchanged across every shipped Win10/11 build — the table layout simply hasn't moved this entry. Note that the kernel performs the copy via a transient mapping; it does not require the page in the target to be writable from userland, only that the section permissions allow kernel writes. That is why injecting into read-only pages still succeeds in many cases.

Common malware usage

The `Write` step of the classic OpenProcess → VirtualAllocEx → WriteProcessMemory → CreateRemoteThread chain. Used to land shellcode, an IAT-fixed PE, or a reflective loader stub into a remote process. Beyond shellcode injection it is also abused to overwrite function prologues for inline hooking, to patch `AMSI.dll!AmsiScanBuffer` or `clr.jit!compileMethod` for AMSI/ETW bypasses, and as the write primitive in PPID-spoofing and process-doppelgänging variants. Brute Ratel, Cobalt Strike, Sliver, Qakbot and IcedID all rely on it as part of their loader chain.

Cobalt StrikeBrute RatelSliverQakbotIcedIDPikaBot

Detection opportunities

Cross-process writes are surfaced primarily through Sysmon Event ID 10 (`ProcessAccess`) when the requested access mask contains `PROCESS_VM_WRITE` (0x0020) or `PROCESS_VM_OPERATION` (0x0008). The ETW Threat Intelligence provider also emits write notifications on certain protected processes. EDRs hook `NtWriteVirtualMemory` in ntdll; direct syscalls bypass the hook but the kernel still updates target VAD reference counts and can be observed via `PsSetCreateProcessNotifyRoutineEx` callbacks if the write triggers a later thread creation. Writes targeting other-session processes, or processes with `lsass.exe`/browser binaries as the target, deserve elevated scoring.

Direct syscall examples

asmx64 direct stub

; Direct syscall stub for NtWriteVirtualMemory (SSN 0x3A, stable across all Win10/11)
NtWriteVirtualMemory PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 3Ah          ; SSN
    syscall
    ret
NtWriteVirtualMemory ENDP

cRemote shellcode injection

// Write shellcode into a previously-allocated remote region.
SIZE_T written = 0;
NTSTATUS st = NtWriteVirtualMemory(hRemote, remote_base,
                                   shellcode, shellcode_len, &written);
if (!NT_SUCCESS(st) || written != shellcode_len) {
    // partial write: typically PAGE_NOACCESS encountered halfway
    return st;
}

rustHell's Gate indirect syscall

// Cargo: ntapi = "0.4"
use std::arch::asm;

#[unsafe(naked)]
unsafe extern "system" fn nt_write_virtual_memory_stub() {
    // SSN 0x3A across every supported build.
    asm!(
        "mov r10, rcx",
        "mov eax, 0x3A",
        "syscall",
        "ret",
        options(noreturn),
    );
}

MITRE ATT&CK mappings

Last verified: 2026-05-20