> Windows Syscalls
ntoskrnl.exeT1106T1027.013

NtResetEvent

Resets an event object to non-signaled and returns its previous signaled state.

Prototype

NTSTATUS NtResetEvent(
  HANDLE  EventHandle,
  PLONG   PreviousState
);

Arguments

NameTypeDirDescription
EventHandleHANDLEinHandle to the event with EVENT_MODIFY_STATE access.
PreviousStatePLONGoutOptional; receives the signaled state of the event before reset (1 = was signaled, 0 = was not).

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x15Ewin10-1507
Win10 16070x165win10-1607
Win10 17030x16Bwin10-1703
Win10 17090x16Ewin10-1709
Win10 18030x170win10-1803
Win10 18090x171win10-1809
Win10 19030x172win10-1903
Win10 19090x172win10-1909
Win10 20040x178win10-2004
Win10 20H20x178win10-20h2
Win10 21H10x178win10-21h1
Win10 21H20x17Awin10-21h2
Win10 22H20x17Awin10-22h2
Win11 21H20x182win11-21h2
Win11 22H20x185win11-22h2
Win11 23H20x185win11-23h2
Win11 24H20x187win11-24h2
Server 20160x165winserver-2016
Server 20190x171winserver-2019
Server 20220x180winserver-2022
Server 20250x187winserver-2025

Kernel module

ntoskrnl.exeNtResetEvent

Related APIs

ResetEventNtSetEventNtClearEventNtPulseEventNtWaitForSingleObject

Syscall stub

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

NtResetEvent is the inverse of NtSetEvent: it drives an event object to the non-signaled state and optionally returns the *previous* state via `PreviousState`. The distinction from NtClearEvent (which does the same drop-to-non-signaled but discards the previous state) is purely whether the caller cares about the prior value — useful for implementing test-and-clear semantics without an extra NtQueryEvent round-trip. The kernel routine `KeResetEvent` underlies both NtResetEvent and NtClearEvent.

Common malware usage

Common in *sleep-mask* and *event-driven idle* implementations used by modern beacons. A typical pattern: the implant arms an event with NtSetEvent before sleeping on a counterpart, then resets it via NtResetEvent on resume to be ready for the next loop iteration. Cobalt Strike's user-defined sleep mask, Sleepmask-rs and various Sliver post-ex modules use NT event primitives this way to avoid the obvious `NtDelayExecution` timing fingerprint. Also seen in worker-thread loops that gate execution on a master signal.

Detection opportunities

NtResetEvent is *extremely* common in legitimate code (every CRITICAL_SECTION on contention, every async I/O completion teardown) so on its own it carries no signal. What matters is correlation: short repeating cycles of `NtCreateEvent → NtSetEvent → NtWait → NtResetEvent` from a single thread with an RWX stack region or with the call sequence inside a heap-allocated buffer is consistent with a sleep-mask. ETW Threat Intelligence (`Microsoft-Windows-Threat-Intelligence`) surfaces some context-switch and wait transitions that can be correlated; otherwise rely on stack-walking telemetry.

Direct syscall examples

asmx64 direct stub

; Direct syscall stub for NtResetEvent (SSN 0x187 on Win11 24H2)
NtResetEvent PROC
    mov  r10, rcx          ; EventHandle
    mov  eax, 187h         ; SSN — verify per-build
    syscall
    ret
NtResetEvent ENDP

cTest-and-clear without round-trip

// Atomically clear hEvent and learn whether it was previously signaled.
#include <windows.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI *pNtResetEvent)(HANDLE, PLONG);

BOOL ConsumeOneShot(HANDLE hEvent) {
    LONG prev = 0;
    pNtResetEvent fn = (pNtResetEvent)GetProcAddress(
        GetModuleHandleA("ntdll.dll"), "NtResetEvent");
    NTSTATUS s = fn(hEvent, &prev);
    return (s >= 0) && (prev != 0);
}

rustEvent-paced sleep mask skeleton

// Cargo: windows-sys = "0.59", ntapi = "0.4"
// Toy sleep-mask loop: park on event, decrypt-process-encrypt, reset, repeat.
use ntapi::ntpsapi::NtResetEvent;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::Threading::WaitForSingleObject;

unsafe fn beacon_loop(wake: HANDLE) {
    loop {
        WaitForSingleObject(wake, u32::MAX);   // park
        // ... unmask payload, run task, remask payload ...
        let mut prev: i32 = 0;
        NtResetEvent(wake, &mut prev);          // rearm for next pulse
    }
}

MITRE ATT&CK mappings

Last verified: 2026-05-20