> Windows Syscalls
ntoskrnl.exeT1620T1574T1106

NtCreateEnclave

Asigna una nueva enclave (SGX o VBS/VTL1) en el espacio de direcciones de un proceso objetivo.

Prototipo

NTSTATUS NtCreateEnclave(
  HANDLE    ProcessHandle,
  PVOID    *BaseAddress,
  ULONG_PTR ZeroBits,
  SIZE_T    Size,
  SIZE_T    InitialCommitment,
  ULONG     EnclaveType,
  PVOID     EnclaveInformation,
  ULONG     EnclaveInformationLength,
  PSIZE_T   EnclaveError
);

Argumentos

NameTypeDirDescription
ProcessHandleHANDLEinHandle al proceso anfitrión. NtCurrentProcess() ((HANDLE)-1) es el único valor práctico.
BaseAddressPVOID*in/outPuntero a la base solicitada. NULL deja al kernel elegir. Recibe la base elegida en éxito.
ZeroBitsULONG_PTRinNúmero de bits altos en cero en BaseAddress. Típicamente 0.
SizeSIZE_TinTamaño total del rango de direcciones de la enclave en bytes. Potencia de dos en SGX; alineado a página en VBS.
InitialCommitmentSIZE_TinBytes inicialmente confirmados; el resto se reserva. 0 para sólo reservar.
EnclaveTypeULONGinENCLAVE_TYPE_SGX (1), ENCLAVE_TYPE_SGX2 (2) o ENCLAVE_TYPE_VBS (0x10). SGX está deprecado tras 2024.
EnclaveInformationPVOIDinEstructura de creación específica del tipo: ENCLAVE_CREATE_INFO_SGX o ENCLAVE_CREATE_INFO_VBS (owner ID + flags).
EnclaveInformationLengthULONGinTamaño en bytes de EnclaveInformation.
EnclaveErrorPSIZE_ToutRecibe el código de error hardware/securekernel cuando NTSTATUS es STATUS_ENCLAVE_FAILURE.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 16070x9Ewin10-1607
Win10 17030xA1win10-1703
Win10 17090xA2win10-1709
Win10 18030xA3win10-1803
Win10 18090xA3win10-1809
Win10 19030xA4win10-1903
Win10 19090xA4win10-1909
Win10 20040xA8win10-2004
Win10 20H20xA8win10-20h2
Win10 21H10xA8win10-21h1
Win10 21H20xA9win10-21h2
Win10 22H20xA9win10-22h2
Win11 21H20xABwin11-21h2
Win11 22H20xACwin11-22h2
Win11 23H20xACwin11-23h2
Win11 24H20xAEwin11-24h2
Server 20160x9Ewinserver-2016
Server 20190xA3winserver-2019
Server 20220xABwinserver-2022
Server 20250xAEwinserver-2025

Módulo del kernel

ntoskrnl.exeNtCreateEnclave

APIs relacionadas

CreateEnclaveNtInitializeEnclaveNtLoadEnclaveDataNtCallEnclaveNtTerminateEnclaveIsEnclaveTypeSupportedDeleteEnclave

Stub del syscall

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

`NtCreateEnclave` es el punto de entrada a las dos tecnologías de enclaves de Windows: **Intel SGX** (`ENCLAVE_TYPE_SGX`/`SGX2`) y las **enclaves de Virtualization-Based Security** (`ENCLAVE_TYPE_VBS` = 0x10). SGX está prácticamente muerta — Intel retiró SGX del Core de 12ª gen y Microsoft viene depreciando la API desde 2024. Las enclaves VBS son la primitiva estratégica: un trozo de espacio de direcciones en un proceso de modo usuario cuyo código y datos se ejecutan en **VTL1** (Virtual Trust Level 1), un nivel de confianza más privilegiado gestionado por el **Secure Kernel** (securekernel.exe) sobre Hyper-V. Desde la perspectiva del proceso anfitrión la enclave es un rango normal de memoria; desde la del *kernel* es opaca — VTL0 (donde corre ntoskrnl) no puede leer ni escribir páginas de VTL1. La creación requiere `SeEnableVirtualizationPrivilege` (sólo lo poseen procesos firmados que se afiliaron vía `IMAGE_ENCLAVE_CONFIG`) y la imagen final debe estar firmada Authenticode con un certificado de firma de enclave emitido por Microsoft (o ser una enclave de depuración en máquina test-signed). El anfitrión enlaza con `vertdll.dll`, que marshala la secuencia create/init/call/load al modelo trustlet vecino de LSASS (`LsaIso.exe`). Usuarios en producción hoy: **Credential Guard**, **vTPM**, **atestación de Win32k** y algunas implementaciones de investigación de Microsoft.

Uso común por malware

Las enclaves son una **primitiva ofensiva en fase de investigación**, todavía no un elemento fijo del malware comoditizado. El atractivo es estructural: los drivers EDR en VTL0 (Microsoft, CrowdStrike, SentinelOne, Defender) **no pueden leer memoria VTL1** — Hyper-V rechaza el mapeo. Por eso el shellcode alojado en una enclave es invisible a los escaneos AV en modo kernel; los callbacks del kernel se disparan sólo a posteriori, sobre los *efectos colaterales*. Trabajos públicos notables: **Schenk & Park (Black Hat USA 2022)** sobre aislamiento de enclave; **Yuste / Soriano-Salvador (Recon 2023)** demostraron un cargador de enclave VBS para shellcode no firmado abusando de un stub cargador firmado; **TrustedSec** y **MDSec** publicaron PoC. La barrera práctica es el *requisito de firma* — el abuso requiere hoy (a) una clave de enclave Microsoft robada, (b) una vulnerabilidad de trustlet con clave privada de code-signing, o (c) un cargador de enclave firmado por Microsoft con un bug de corrupción de memoria (la vía más realista). Ninguna familia ampliamente atribuida in-the-wild usa enclaves todavía.

Oportunidades de detección

La creación de enclave es **casi nula en un endpoint normal** — ésa es toda la estrategia de detección. El proveedor ETW `Microsoft-Windows-Kernel-Memory` emite eventos al crearse una enclave VBS; `Microsoft-Windows-Hyper-V-Worker` muestra actividad VTL1. En Win11 24H2, `Microsoft-Windows-Security-Mitigations/KernelMode` incluye el ciclo de vida de la enclave. Hunt práctico: listar procesos con el derecho `SeEnableVirtualizationPrivilege`, contrastar con la presencia de directorio `IMAGE_ENCLAVE_CONFIG` en sus módulos cargados y alertar sobre todo lo que **no** sea `lsass.exe`, `LsaIso.exe`, pares de `securekernel.exe` o trustlets Microsoft conocidos. Los EDR *no ven* la ejecución dentro de la enclave, pero sí ven la secuencia syscall `NtCreateEnclave` / `NtLoadEnclaveData` / `NtInitializeEnclave` del proceso anfitrión — hookéelos (o coseche ETW kernel-syscall) y trate la cadena como una señal de alta fidelidad fuera de `lsass`. Defender usa la capa HVCI para rechazar imágenes de enclave no firmadas; nunca deshabilite HVCI en un entorno gestionado.

Ejemplos de syscalls directos

cVBS enclave bring-up (step 1/3 — create)

// Minimal VBS enclave creation skeleton. Requires:
//   * Host binary compiled with /ENCLAVE flag and an IMAGE_ENCLAVE_CONFIG directory
//   * Enclave DLL Authenticode-signed with a Microsoft-issued enclave cert
//   * SeEnableVirtualizationPrivilege available (granted to host by signing policy)
// See NtInitializeEnclave + NtCallEnclave for the rest of the lifecycle.
#include <windows.h>
#include <ntsecapi.h>

typedef struct _ENCLAVE_CREATE_INFO_VBS {
    ULONG Flags;           // 0 or ENCLAVE_VBS_FLAG_DEBUG
    UCHAR OwnerID[32];     // 32-byte owner identity
} ENCLAVE_CREATE_INFO_VBS;

PVOID CreateVbsEnclave(SIZE_T size) {
    ENCLAVE_CREATE_INFO_VBS info = {0};
    info.Flags = ENCLAVE_VBS_FLAG_DEBUG; // omit in production
    // OwnerID can be left zero for a single-owner test enclave
    PVOID base = CreateEnclave(
        GetCurrentProcess(),
        NULL,                  // let kernel choose base
        size,
        0,                     // initial commit = 0
        ENCLAVE_TYPE_VBS,
        &info, sizeof(info),
        NULL);                 // enclaveError
    if (!base) {
        DWORD ec = GetLastError(); // NTSTATUS-mapped
        return NULL;
    }
    return base;
}

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtCreateEnclave (SSN 0xAE on Win11 24H2 / Server 2025)
; Note: enclave SSNs drift across builds — resolve dynamically for portable code.
NtCreateEnclave PROC
    mov  r10, rcx          ; ProcessHandle
    mov  eax, 0AEh         ; SSN
    syscall
    ret
NtCreateEnclave ENDP

rustwindows-sys CreateEnclave wrapper

// Cargo: windows-sys = { version = "0.59", features = [
//     "Win32_System_Threading", "Win32_Foundation", "Win32_System_Memory"
// ] }
use std::ptr::{null, null_mut};
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::Threading::GetCurrentProcess;

#[repr(C)]
struct EnclaveCreateInfoVbs {
    flags: u32,
    owner_id: [u8; 32],
}

extern "system" {
    fn CreateEnclave(
        process: HANDLE, base: *const u8, size: usize, initial_commit: usize,
        ty: u32, info: *const core::ffi::c_void, info_len: u32, err: *mut u32,
    ) -> *mut core::ffi::c_void;
}

const ENCLAVE_TYPE_VBS: u32 = 0x10;
const ENCLAVE_VBS_FLAG_DEBUG: u32 = 1;

pub unsafe fn create_vbs_enclave(size: usize) -> Option<*mut core::ffi::c_void> {
    let info = EnclaveCreateInfoVbs { flags: ENCLAVE_VBS_FLAG_DEBUG, owner_id: [0u8; 32] };
    let mut enclave_err: u32 = 0;
    let base = CreateEnclave(
        GetCurrentProcess(), null(), size, 0,
        ENCLAVE_TYPE_VBS,
        &info as *const _ as *const _, core::mem::size_of::<EnclaveCreateInfoVbs>() as u32,
        &mut enclave_err,
    );
    if base.is_null() { None } else { Some(base) }
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20