> Windows Syscalls
ntoskrnl.exeT1620T1574T1106

NtCallEnclave

Transfiere la ejecución desde el código anfitrión VTL0 a una rutina dentro de una enclave inicializada.

Prototipo

NTSTATUS NtCallEnclave(
  PVOID    Routine,
  PVOID    Parameter,
  BOOLEAN  WaitForThread,
  PVOID   *ReturnValue
);

Argumentos

NameTypeDirDescription
RoutinePVOIDinDirección VTL1 de la función de entrada de la enclave. Debe estar dentro del rango de la enclave inicializada y exportarse vía la config de enclave.
ParameterPVOIDinParámetro opaco único pasado a la rutina de enclave en RCX. Típicamente un puntero a un buffer de petición asignado por el anfitrión.
WaitForThreadBOOLEANinTRUE bloquea hasta que haya un hilo de enclave libre; FALSE devuelve STATUS_ENCLAVE_NOT_TERMINATED si todos los hilos reservados están ocupados.
ReturnValuePVOID*outRecibe el valor PVOID devuelto por la rutina de enclave (su RAX al retornar a VTL0).

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 17090x8Ewin10-1709
Win10 18030x8Fwin10-1803
Win10 18090x8Fwin10-1809
Win10 19030x8Fwin10-1903
Win10 19090x8Fwin10-1909
Win10 20040x91win10-2004
Win10 20H20x91win10-20h2
Win10 21H10x91win10-21h1
Win10 21H20x91win10-21h2
Win10 22H20x91win10-22h2
Win11 21H20x91win11-21h2
Win11 22H20x91win11-22h2
Win11 23H20x91win11-23h2
Win11 24H20x93win11-24h2
Server 20190x8Fwinserver-2019
Server 20220x91winserver-2022
Server 20250x93winserver-2025

Módulo del kernel

ntoskrnl.exeNtCallEnclave

APIs relacionadas

CallEnclaveNtCreateEnclaveNtInitializeEnclaveNtLoadEnclaveDataNtTerminateEnclaveGetProcAddressForCaller

Stub del syscall

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

`NtCallEnclave` es la llamada de **conmutación de mundo**. Internamente ejecuta un `EENTER` en SGX o un `VMCALL` al Secure Kernel para VBS — ambos transfieren al final la CPU lógica del hilo anfitrión a VTL1 con un contexto pila/registros guardado. La rutina de enclave corre con una pila *fresca* dentro del rango reservado de la enclave; jamás puede tocar memoria del anfitrión VTL0 directamente. Para mover datos, la enclave lee `Parameter` (una dirección VTL0 que el Secure Kernel marshala en la entrada) y devuelve un valor por `*ReturnValue`. La reentrada está limitada por `ThreadCount` de `NtInitializeEnclave`. El envoltorio en modo usuario `CallEnclave` es un shim fino sobre este syscall — toma `Routine` de la tabla de exports de la enclave.

Uso común por malware

Ésta es la llamada que **ejecuta código atacante en VTL1**, pero sólo después de que la cadena create/load/initialize ha pasado las verificaciones de firma. Rutas realistas: (1) llamar a una enclave *firmada por Microsoft* con parámetros que disparen una vulnerabilidad conocida — la enclave entonces ejecuta la lógica del atacante con ceguera del EDR VTL0; (2) llamar a una enclave *loader de investigación* (p. ej. el stub Yuste / Soriano-Salvador) que acepta intencionalmente un puntero a shellcode arbitrario en `Parameter` y salta a él dentro de VTL1. Una vez dentro, la enclave puede usar `NtCallEnclave` con `Routine = dirección fuera de enclave` para retro-llamar al anfitrión (el mecanismo `CallEnclave` es bidireccional); ésta es la vía que usa la investigación tipo Recon para emitir syscalls normales (p. ej. `NtAllocateVirtualMemory`) desde dentro de la enclave. El EDR ve el syscall del anfitrión pero no puede atribuirlo al hilo de la enclave.

Oportunidades de detección

La telemetría directa desde dentro de la enclave es imposible desde VTL0 — por diseño. Pivotar en (a) la *frecuencia* de `NtCallEnclave` por proceso (los trustlets legítimos lo invocan a cadencia estable; una herramienta atacante suele mostrar un pico en el momento del ataque), (b) el patrón *callout*: una enclave que de inmediato se gira y vuelve a llamar a VTL0 para invocar `NtAllocateVirtualMemory`/`NtWriteVirtualMemory` es sospechosa. El proveedor ETW `Microsoft-Windows-Kernel-Memory` (evento 5) traza entradas/salidas de enclave pero no está activo por defecto — activarlo en endpoints de alto valor. Desde un driver de kernel, `KeRegisterEnclaveCallback` *no* existe; no puede interceptar la llamada de enclave desde un driver normal. La señal debe venir de la secuencia syscall del anfitrión.

Ejemplos de syscalls directos

cVBS enclave bring-up (step 4 — call into VTL1)

// Final step of a minimal enclave session: invoke a named export inside the enclave.
// 'enclaveBase' came from CreateEnclave; 'EnclaveEntry' is exported by the signed enclave DLL.
#include <windows.h>

typedef int (*PENCLAVE_ENTRY)(void *param);

int InvokeEnclave(PVOID enclaveBase, PVOID hostRequest) {
    PENCLAVE_ENTRY entry = (PENCLAVE_ENTRY)GetProcAddressForCaller(
        enclaveBase, "EnclaveEntry");
    PVOID retVal = NULL;
    if (!CallEnclave(entry, hostRequest, TRUE /*WaitForThread*/, &retVal)) {
        return -1;
    }
    return (int)(INT_PTR)retVal;
}

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtCallEnclave (SSN 0x93 on Win11 24H2 / Server 2025)
; SSN was 0x91 from Win10 2004 through Win11 23H2 — stable for ~5 years.
NtCallEnclave PROC
    mov  r10, rcx          ; Routine
    mov  eax, 93h          ; SSN
    syscall
    ret
NtCallEnclave ENDP

rustwindows-sys CallEnclave

// Cargo: windows-sys = { version = "0.59", features = ["Win32_System_Threading"] }
use std::ptr::null_mut;
use windows_sys::core::BOOL;

extern "system" {
    fn CallEnclave(
        routine: *const core::ffi::c_void,
        param: *mut core::ffi::c_void,
        wait_for_thread: BOOL,
        ret: *mut *mut core::ffi::c_void,
    ) -> BOOL;
}

pub unsafe fn call_enclave_entry(
    routine: *const core::ffi::c_void,
    request: *mut core::ffi::c_void,
) -> Option<*mut core::ffi::c_void> {
    let mut ret: *mut core::ffi::c_void = null_mut();
    if CallEnclave(routine, request, 1 /*TRUE*/, &mut ret) == 0 {
        return None;
    }
    Some(ret)
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20