> Windows Syscalls
ntoskrnl.exeT1027.011T1106T1029

NtCreateTimer

Creates a kernel timer object that can be armed later with NtSetTimer.

Prototype

NTSTATUS NtCreateTimer(
  PHANDLE            TimerHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes,
  TIMER_TYPE         TimerType
);

Arguments

NameTypeDirDescription
TimerHandlePHANDLEoutReceives the handle to the newly created timer object.
DesiredAccessACCESS_MASKinAccess mask, typically TIMER_ALL_ACCESS or TIMER_MODIFY_STATE | SYNCHRONIZE.
ObjectAttributesPOBJECT_ATTRIBUTESinOptional object attributes; NULL for anonymous, name under \BaseNamedObjects for IPC use.
TimerTypeTIMER_TYPEinNotificationTimer (broadcast, stays signaled) or SynchronizationTimer (auto-reset).

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070xB4win10-1507
Win10 16070xB7win10-1607
Win10 17030xBAwin10-1703
Win10 17090xBBwin10-1709
Win10 18030xBCwin10-1803
Win10 18090xBDwin10-1809
Win10 19030xBEwin10-1903
Win10 19090xBEwin10-1909
Win10 20040xC2win10-2004
Win10 20H20xC2win10-20h2
Win10 21H10xC2win10-21h1
Win10 21H20xC3win10-21h2
Win10 22H20xC3win10-22h2
Win11 21H20xC8win11-21h2
Win11 22H20xC9win11-22h2
Win11 23H20xC9win11-23h2
Win11 24H20xCBwin11-24h2
Server 20160xB7winserver-2016
Server 20190xBDwinserver-2019
Server 20220xC7winserver-2022
Server 20250xCBwinserver-2025

Kernel module

ntoskrnl.exeNtCreateTimer

Related APIs

CreateWaitableTimerWCreateWaitableTimerExWCreateTimerQueueCreateTimerQueueTimerNtCreateTimerExNtSetTimerNtCancelTimer

Syscall stub

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

Allocates an executive `KTIMER` object via `ExCreateTimer` / `ObCreateObject`. The object is *unarmed* at creation — it does nothing until `NtSetTimer` provides a due time and optional APC routine. SSN drifts across builds (`0xB4` on 1507 → `0xCB` on Win11 24H2 / Server 2025), so direct-syscall implementations must resolve dynamically. `NotificationTimer` keeps the dispatcher object signaled after expiry (all waiters released and stay through), while `SynchronizationTimer` auto-resets after releasing one waiter — the latter is what sleep-mask designs use.

Common malware usage

The first half of the **Ekko sleep-mask engine** (Austin Hudson, 2022) — and the design copied wholesale by Foliage, Cronos, Zilean and most modern fork-derived crypter loaders. A timer is created, then `NtSetTimer` arms it with `TimerApcRoutine = RtlCaptureContext`/`SetEvent`/`VirtualProtect` chain stages, and the implant performs an alertable wait. Each timer expiry queues an APC, the APC runs a ROP-stage that re-encrypts the implant memory and re-arms — producing a beacon whose code is RWX → RW → encrypted on every cycle, defeating naive memory scanners. NtCreateTimer alone is benign; the *triad* (timer + event + alertable wait inside private memory) is the IOC.

Detection opportunities

No dedicated Sysmon event for timer creation. ETW `Microsoft-Windows-Kernel-Object` with the `Timer` keyword exposes object creation; correlating timer handles held by a thread whose RIP at the moment of `NtSetTimer` lies in unbacked / RWX memory is the high-fidelity signal. Most EDRs that defeat Ekko do it by scanning the suspended thread's stack and walking back through KiUserApcDispatcher frames at the moment a special user APC delivers — they catch the encryption stage in flight rather than the timer creation itself.

Direct syscall examples

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtCreateTimer (SSN 0xCB on Win11 24H2 / Server 2025)
NtCreateTimer PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 0CBh         ; SSN — drifts; resolve dynamically for portability
    syscall
    ret
NtCreateTimer ENDP

cEkko-style sleep-mask timer setup

// Step 1 of the sleep-mask triad: a synchronization timer the APC chain will arm.
HANDLE             hTimer = NULL;
OBJECT_ATTRIBUTES  oa     = { sizeof(oa), 0 };
NTSTATUS st = NtCreateTimer(&hTimer,
                            TIMER_ALL_ACCESS,
                            &oa,
                            SynchronizationTimer);
if (!NT_SUCCESS(st)) return st;
// hTimer will be armed by NtSetTimer with TimerApcRoutine pointing at the ROP gadgets.

rustwindows-sys CreateWaitableTimerW wrapper

// Cargo: windows-sys = "0.59" (Win32_System_Threading)
use windows_sys::Win32::System::Threading::CreateWaitableTimerW;
use std::ptr::null;

unsafe fn make_timer() -> *mut core::ffi::c_void {
    // bManualReset = 0 → SynchronizationTimer kernel-side.
    CreateWaitableTimerW(null(), 0, null())
}

MITRE ATT&CK mappings

Last verified: 2026-05-20