> Windows Syscalls
ntoskrnl.exeT1497T1497.003T1027.011

NtDelayExecution

Suspende el hilo llamante durante un intervalo dado, opcionalmente en estado alertable.

Prototipo

NTSTATUS NtDelayExecution(
  BOOLEAN        Alertable,
  PLARGE_INTEGER DelayInterval
);

Argumentos

NameTypeDirDescription
AlertableBOOLEANinSi TRUE, la espera puede interrumpirse por una APC encolada; si FALSE, el hilo duerme de forma no alertable.
DelayIntervalPLARGE_INTEGERinUnidades de 100 ns. Negativo = retardo relativo (lo más común); positivo = tiempo UTC absoluto.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x34win10-1507
Win10 16070x34win10-1607
Win10 17030x34win10-1703
Win10 17090x34win10-1709
Win10 18030x34win10-1803
Win10 18090x34win10-1809
Win10 19030x34win10-1903
Win10 19090x34win10-1909
Win10 20040x34win10-2004
Win10 20H20x34win10-20h2
Win10 21H10x34win10-21h1
Win10 21H20x34win10-21h2
Win10 22H20x34win10-22h2
Win11 21H20x34win11-21h2
Win11 22H20x34win11-22h2
Win11 23H20x34win11-23h2
Win11 24H20x34win11-24h2
Server 20160x34winserver-2016
Server 20190x34winserver-2019
Server 20220x34winserver-2022
Server 20250x34winserver-2025

Módulo del kernel

ntoskrnl.exeNtDelayExecution

APIs relacionadas

SleepSleepExSleepConditionVariableSRWWaitForSingleObjectExNtWaitForSingleObjectNtYieldExecution

Stub del syscall

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

Notas no documentadas

Las APIs Win32 `Sleep` y `SleepEx` son envoltorios delgados sobre `NtDelayExecution`. El SSN ha sido `0x34` en cada build publicado de Win10/11, siendo uno de los más predecibles en user-mode. El kernel encamina la llamada por `KeDelayExecutionThread` y termina bloqueando en el dispatcher de timers. Una llamada con intervalo relativo cero o NULL cede el resto del quantum — equivalente a `SwitchToThread()`.

Uso común por malware

Primitiva canónica de evasión por tiempo / anti-sandbox (MITRE T1497.003). Sleeps largos no alertables (5–30 min) sirven para superar la ventana de análisis de sandboxes automáticos que sólo observan una muestra 1–2 minutos. Frameworks modernos de sleep mask (Ekko, Foliage, Cronos, Sleep Mask Kit de Cobalt Strike, Brute Ratel C4) encierran `NtDelayExecution` entre cifrado y descifrado: el `.text` y el heap del beacon se cifran in-place, se llama a `NtDelayExecution`, y al despertar se descifra — un escaneo de memoria durante el sueño sólo encuentra cifrado. Combinado con un `ntdll!NtDelayExecution` no hookeado o syscall directo/indirecto, evade los hooks de EDR en user-mode durante la dormancia.

Oportunidades de detección

La detección es difícil porque `Sleep` es universal. Telemetría útil: sleeps anormalmente largos desde procesos no interactivos; bucles `NtQuerySystemTime` → `NtDelayExecution` (chequeo de aceleración de sandbox); snapshots de pila de hilo donde la dirección de retorno apunta a memoria RWX/privada en vez de a un módulo cargado (firma de beacon dormido). El proveedor ETW `Microsoft-Windows-Kernel-Process` y Threat Intelligence exponen razones de espera. Los EDRs escanean cada vez más la memoria RX privada periódicamente para detectar implantes con sleep mask entre cifrado y descifrado.

Ejemplos de syscalls directos

asmx64 direct stub

; Direct syscall stub for NtDelayExecution (SSN 0x34, all Win10/11 builds)
NtDelayExecution PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 34h          ; SSN
    syscall
    ret
NtDelayExecution ENDP

cSandbox time-skip detector

// Sleep 10 s of wall time, verify the kernel actually slept that long.
// Sandboxes that patch Sleep / accelerate timers will return early.
#include <windows.h>
#include <winternl.h>

extern "C" NTSTATUS NTAPI NtDelayExecution(BOOLEAN, PLARGE_INTEGER);
extern "C" NTSTATUS NTAPI NtQuerySystemTime(PLARGE_INTEGER);

BOOL LooksLikeSandbox(void) {
    LARGE_INTEGER t0, t1, delay;
    NtQuerySystemTime(&t0);
    delay.QuadPart = -10LL * 10000000LL;       // 10 s, relative
    NtDelayExecution(FALSE, &delay);
    NtQuerySystemTime(&t1);
    LONGLONG elapsedSec = (t1.QuadPart - t0.QuadPart) / 10000000LL;
    return elapsedSec < 9;                      // sandbox skipped the sleep
}

rustNaked sleep stub (windows-sys)

// Cargo: windows-sys = "0.59"
use std::arch::asm;

#[unsafe(naked)]
unsafe extern "system" fn nt_delay_execution(
    _alertable: u8,
    _interval: *const i64,
) -> i32 {
    asm!(
        "mov r10, rcx",
        "mov eax, 0x34",
        "syscall",
        "ret",
        options(noreturn),
    );
}

pub fn sleep_seconds(s: i64) {
    // 100 ns units, negative = relative
    let interval: i64 = -s * 10_000_000;
    unsafe { nt_delay_execution(0, &interval as *const _); }
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20