> Windows Syscalls
ntoskrnl.exeT1106T1027.011T1480

NtCreateEvent

Creates a named or unnamed event synchronization object and returns a handle to it.

Prototype

NTSTATUS NtCreateEvent(
  PHANDLE            EventHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes,
  EVENT_TYPE         EventType,
  BOOLEAN            InitialState
);

Arguments

NameTypeDirDescription
EventHandlePHANDLEoutReceives the handle to the newly created event object on success.
DesiredAccessACCESS_MASKinAccess mask, e.g. EVENT_ALL_ACCESS, EVENT_MODIFY_STATE, SYNCHRONIZE.
ObjectAttributesPOBJECT_ATTRIBUTESinOptional object attributes. NULL for unnamed; supply a name under \BaseNamedObjects for IPC.
EventTypeEVENT_TYPEinNotificationEvent (manual reset) or SynchronizationEvent (auto-reset).
InitialStateBOOLEANinTRUE if the event is initially signaled, FALSE if non-signaled.

Syscall IDs by Windows version

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

Kernel module

ntoskrnl.exeNtCreateEvent

Related APIs

CreateEventWCreateEventExWOpenEventWSetEventResetEventNtOpenEventNtSetEventNtWaitForSingleObject

Syscall stub

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

Creates an executive event object via ObCreateObject + KeInitializeEvent inside ntoskrnl.exe. SSN `0x48` has been stable across every Win10 and Win11 build to date. Two `EVENT_TYPE` values matter: `NotificationEvent` stays signaled until manually reset (broadcast semantics), while `SynchronizationEvent` automatically resets after one waiter is released (semaphore-of-one semantics). When an `ObjectAttributes` name under `\BaseNamedObjects` is supplied, the event becomes a cross-process IPC primitive — any process that can `NtOpenEvent` the name shares the same kernel object.

Common malware usage

Used as the synchronization backbone of modern sleep masks (Ekko, Foliage, Cronos, Zilean): the implant creates an auto-reset event, queues a timer whose APC routine signals it, then waits on it inside an alertable wait — letting the ROP chain re-encrypt the implant region between beacons. Also forms half of named-pipe-and-event C2 designs (Brute Ratel C4, Sliver pivot pipes) where the named event signals "command available" without a polling loop. A signaled named event is a common single-instance check too.

Detection opportunities

Event creation is high-volume in every Windows process and is not a useful standalone signal. Detection focuses on the *name* and the *handle owner*: events named like `Global\<random-guid>` opened cross-process from non-system parents, or events whose handle is held by a process that also holds a writable section + a timer (the Ekko triad). Sysmon does not log event creation directly; ETW `Microsoft-Windows-Kernel-Object` and Object Manager handle audits can be enabled selectively. EDRs that walk handle tables on suspend / sleep transitions catch the sleep-mask pattern reliably.

Direct syscall examples

asmx64 direct stub

; Direct syscall stub for NtCreateEvent (SSN 0x48, stable across Win10/11)
NtCreateEvent PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 48h          ; SSN
    syscall
    ret
NtCreateEvent ENDP

cEkko sleep-mask event setup

// Auto-reset event signalled by a timer APC; waited on alertably to drive the chain.
HANDLE             hEvent  = NULL;
OBJECT_ATTRIBUTES  oa      = { sizeof(oa), 0 };
NTSTATUS st = NtCreateEvent(&hEvent,
                            EVENT_ALL_ACCESS,
                            &oa,
                            SynchronizationEvent,
                            FALSE);
if (!NT_SUCCESS(st)) return st;
// hEvent is now the rendezvous point between the implant thread and the timer APC.

rustwindows-sys named event for single-instance

// Cargo: windows-sys = "0.59" (Win32_System_Threading)
use windows_sys::Win32::System::Threading::CreateEventW;
use windows_sys::Win32::Foundation::{GetLastError, ERROR_ALREADY_EXISTS};
use std::ptr::null;

unsafe fn ensure_single_instance(name: *const u16) -> bool {
    let h = CreateEventW(null(), 1, 0, name);
    if h.is_null() { return false; }
    GetLastError() != ERROR_ALREADY_EXISTS
}

MITRE ATT&CK mappings

Last verified: 2026-05-20