> Windows Syscalls
ntoskrnl.exeT1027.011T1106

NtResetWriteWatch

Clears the write-tracking state of a MEM_WRITE_WATCH region without retrieving the dirty pages.

Prototype

NTSTATUS NtResetWriteWatch(
  HANDLE  ProcessHandle,
  PVOID   BaseAddress,
  SIZE_T  RegionSize
);

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle to the process whose write-watch state is being reset. Usually NtCurrentProcess().
BaseAddressPVOIDinBase address of the MEM_WRITE_WATCH region whose dirty bits should be cleared.
RegionSizeSIZE_TinSize in bytes of the region to reset. Must be within the original allocation.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x15Fwin10-1507
Win10 16070x166win10-1607
Win10 17030x16Cwin10-1703
Win10 17090x16Fwin10-1709
Win10 18030x171win10-1803
Win10 18090x172win10-1809
Win10 19030x173win10-1903
Win10 19090x173win10-1909
Win10 20040x179win10-2004
Win10 20H20x179win10-20h2
Win10 21H10x179win10-21h1
Win10 21H20x17Bwin10-21h2
Win10 22H20x17Bwin10-22h2
Win11 21H20x183win11-21h2
Win11 22H20x186win11-22h2
Win11 23H20x186win11-23h2
Win11 24H20x188win11-24h2
Server 20160x166winserver-2016
Server 20190x172winserver-2019
Server 20220x181winserver-2022
Server 20250x188winserver-2025

Kernel module

ntoskrnl.exeNtResetWriteWatch

Related APIs

ResetWriteWatchGetWriteWatchNtGetWriteWatchVirtualAllocNtAllocateVirtualMemory

Syscall stub

4C 8B D1                  mov r10, rcx
B8 88 01 00 00            mov eax, 0x188
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

NtResetWriteWatch is the standalone reset companion to NtGetWriteWatch. Most callers prefer the atomic form `NtGetWriteWatch(WRITE_WATCH_FLAG_RESET, ...)` because it eliminates the race window between query and reset. The separate syscall is useful when the caller wants to discard dirty information entirely (e.g. after a full re-encryption pass) without paying for the array copy-out of NtGetWriteWatch. The kernel implementation walks the same PTE-level dirty bits cleared by `MiResetWriteWatch`.

Common malware usage

Used by sleep-mask implants that perform a full memory re-encrypt at startup or after a configuration update — the implant doesn't care which pages were dirty, it's encrypting everything anyway, but it still needs to reset the watch state so the *next* incremental encryption pass sees only the truly-dirty pages from the next awake window. Less commonly used standalone than NtGetWriteWatch since the atomic-reset flag exists, but appears in some early-generation sleep masks (pre-Ekko) that decoupled the two phases. Forensic analysis of a paused implant snapshot can sometimes catch the reset call mid-cycle when the dirty bits are momentarily clean.

Detection opportunities

Same kernel-level signal as NtGetWriteWatch — the VAD's `VadWriteWatch` flag is the prerequisite for either syscall to do anything meaningful. NtResetWriteWatch without a preceding (or pending) NtGetWriteWatch on the same range is unusual outside of the .NET GC's start-of-cycle reset path. EDRs with VAD-walk capability can flag any user-mode process holding a sizeable MEM_WRITE_WATCH region with PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE protection — that combination is essentially never seen in benign software and is a hallmark of dirty-page-aware sleep masks.

Direct syscall examples

cStandalone reset after a full pass

// After a full memory rescan / full re-encrypt, drop the dirty bits without
// the cost of copying out the dirty-page array.
#include <windows.h>

void reset_tracking(PVOID region, SIZE_T size) {
    // ResetWriteWatch is the documented Win32 wrapper around NtResetWriteWatch.
    if (ResetWriteWatch(region, size) != 0) {
        // Region was not allocated with MEM_WRITE_WATCH.
    }
}

asmx64 direct stub (Win11 24H2, SSN 0x188)

NtResetWriteWatch PROC
    mov  r10, rcx
    mov  eax, 188h
    syscall
    ret
NtResetWriteWatch ENDP

cTwo-phase sleep mask (pre-Ekko style)

// Phase 1: encrypt every page (full pass), then reset the watch state.
// Phase 2 (next cycle): NtGetWriteWatch reports only newly dirtied pages.
void full_encrypt_and_reset(PVOID region, SIZE_T size) {
    encrypt_full(region, size);
    ResetWriteWatch(region, size);   // ntdll!NtResetWriteWatch under the hood
}

MITRE ATT&CK mappings

Last verified: 2026-05-20