> Windows Syscalls
ntoskrnl.exeT1027.011T1106

NtResetWriteWatch

Efface l'état de suivi d'écriture d'une région MEM_WRITE_WATCH sans récupérer les pages sales.

Prototype

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

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle vers le processus dont l'état write-watch est réinitialisé. Généralement NtCurrentProcess().
BaseAddressPVOIDinAdresse de base de la région MEM_WRITE_WATCH dont les bits dirty doivent être effacés.
RegionSizeSIZE_TinTaille en octets de la région à réinitialiser. Doit être dans l'allocation d'origine.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
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

Module noyau

ntoskrnl.exeNtResetWriteWatch

APIs liées

ResetWriteWatchGetWriteWatchNtGetWriteWatchVirtualAllocNtAllocateVirtualMemory

Stub du syscall

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

Notes non documentées

NtResetWriteWatch est le compagnon de reset autonome de NtGetWriteWatch. La plupart des appelants préfèrent la forme atomique `NtGetWriteWatch(WRITE_WATCH_FLAG_RESET, ...)` car elle élimine la fenêtre de course entre requête et reset. Le syscall séparé est utile quand l'appelant veut écarter entièrement l'information dirty (par ex. après une passe de re-chiffrement complète) sans payer la copie de tableau de NtGetWriteWatch. L'implémentation noyau parcourt les mêmes bits dirty au niveau PTE qu'efface `MiResetWriteWatch`.

Usage courant par les malwares

Utilisé par les implants à sleep-mask qui effectuent un re-chiffrement complet de la mémoire au démarrage ou après une mise à jour de config — l'implant se moque de savoir quelles pages étaient sales, il les chiffre toutes, mais il doit quand même réinitialiser l'état de suivi pour que la *prochaine* passe incrémentale ne voie que les pages vraiment sales de la fenêtre éveillée suivante. Moins utilisé isolément que NtGetWriteWatch puisque le flag reset atomique existe, mais apparaît dans certains sleep-masks de première génération (pré-Ekko) qui découplaient les deux phases. L'analyse forensique d'un snapshot d'implant en pause peut parfois saisir l'appel reset en plein cycle quand les bits dirty sont momentanément propres.

Opportunités de détection

Même signal noyau que NtGetWriteWatch — le drapeau `VadWriteWatch` du VAD est prérequis pour que l'un ou l'autre syscall fasse quoi que ce soit de significatif. NtResetWriteWatch sans un NtGetWriteWatch précédent (ou en attente) sur la même plage est inhabituel hors du chemin reset de début de cycle du GC .NET. Les EDR avec capacité de parcours VAD peuvent signaler tout processus user-mode détenant une région MEM_WRITE_WATCH conséquente avec protection PAGE_EXECUTE_READ ou PAGE_EXECUTE_READWRITE — cette combinaison ne se voit essentiellement jamais dans du logiciel bénin et constitue une signature des sleep-masks dirty-page-aware.

Exemples de syscalls directs

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
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20