> Windows Syscalls
ntoskrnl.exeT1620T1574T1106

NtCreateEnclave

Alloue une nouvelle enclave (SGX ou VBS/VTL1) dans l'espace d'adressage d'un processus cible.

Prototype

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

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle vers le processus hôte. NtCurrentProcess() ((HANDLE)-1) est la seule valeur pratique.
BaseAddressPVOID*in/outPointeur vers la base demandée. NULL laisse le noyau choisir. Reçoit la base retenue en cas de succès.
ZeroBitsULONG_PTRinNombre de bits de poids fort à zéro dans BaseAddress. Typiquement 0.
SizeSIZE_TinTaille totale de la plage d'adresses de l'enclave en octets. Doit être une puissance de deux sur SGX ; aligné page sur VBS.
InitialCommitmentSIZE_TinOctets initialement validés ; le reste est réservé. 0 pour uniquement réserver.
EnclaveTypeULONGinENCLAVE_TYPE_SGX (1), ENCLAVE_TYPE_SGX2 (2) ou ENCLAVE_TYPE_VBS (0x10). SGX déprécié depuis 2024.
EnclaveInformationPVOIDinStructure de création spécifique au type : ENCLAVE_CREATE_INFO_SGX ou ENCLAVE_CREATE_INFO_VBS (owner ID + flags).
EnclaveInformationLengthULONGinTaille en octets de EnclaveInformation.
EnclaveErrorPSIZE_ToutReçoit le code d'erreur matériel / securekernel quand NTSTATUS vaut STATUS_ENCLAVE_FAILURE.

IDs de syscalls par version de Windows

Version 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

Module noyau

ntoskrnl.exeNtCreateEnclave

APIs liées

CreateEnclaveNtInitializeEnclaveNtLoadEnclaveDataNtCallEnclaveNtTerminateEnclaveIsEnclaveTypeSupportedDeleteEnclave

Stub du 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

Notes non documentées

`NtCreateEnclave` est le point d'entrée des deux technologies d'enclave de Windows : **Intel SGX** (`ENCLAVE_TYPE_SGX`/`SGX2`) et les **enclaves Virtualization-Based Security** (`ENCLAVE_TYPE_VBS` = 0x10). SGX est de facto mort — Intel a retiré SGX du Core de 12e gén et Microsoft déprécie l'API depuis 2024. Les enclaves VBS sont la primitive stratégique : un bloc d'espace d'adressage dans un processus user-mode dont le code et les données s'exécutent dans **VTL1** (Virtual Trust Level 1), un niveau de confiance plus privilégié géré par le **Secure Kernel** (securekernel.exe) au-dessus d'Hyper-V. Du point de vue du processus hôte, l'enclave est une plage mémoire normale ; du point de vue du *noyau*, elle est opaque — VTL0 (où tourne ntoskrnl) ne peut ni lire ni écrire les pages VTL1. La création requiert le `SeEnableVirtualizationPrivilege` (détenu uniquement par des processus signés ayant opté via `IMAGE_ENCLAVE_CONFIG`) et l'image d'enclave doit être signée Authenticode avec un certificat enclave émis par Microsoft (ou être une enclave de debug sur machine test-signed). L'hôte se lie à `vertdll.dll` qui marshale la séquence create/init/call/load via le modèle trustlet voisin de LSASS (`LsaIso.exe`). Utilisateurs en production : **Credential Guard**, **vTPM**, **attestation Win32k**, et quelques déploiements de recherche Microsoft.

Usage courant par les malwares

Les enclaves sont une **primitive offensive en phase de recherche**, pas encore un standard du malware commun. L'attrait est structurel : les drivers EDR en VTL0 (Microsoft, CrowdStrike, SentinelOne, Defender) **ne peuvent pas lire la mémoire VTL1** — Hyper-V refuse le mapping. Du shellcode hébergé dans une enclave est donc invisible aux scans AV kernel-mode ; les callbacks noyau ne se déclenchent qu'après coup, sur les *effets de bord* de l'exécution. Travaux publics notables : **Schenk & Park (Black Hat USA 2022) — "A Dirty Little History"** sur l'isolation d'enclave ; **Yuste / Soriano-Salvador (Recon 2023)** ont démontré un loader d'enclave VBS pour shellcode non signé arbitraire en abusant d'un stub loader signé ; **TrustedSec** et **MDSec** ont publié des PoC. La barrière pratique est l'*exigence de signature* — l'abus requiert aujourd'hui (a) une clé enclave Microsoft volée, (b) une vulnérabilité trustlet à clé privée code-signing, ou (c) un loader d'enclave signé Microsoft avec un bug de corruption mémoire (la voie la plus réaliste). Aucune famille in-the-wild largement attribuée n'utilise encore les enclaves.

Opportunités de détection

La création d'enclave est **quasi nulle sur un endpoint normal** — c'est toute la stratégie de détection. Le provider ETW `Microsoft-Windows-Kernel-Memory` émet des événements lors de la création d'enclave VBS ; `Microsoft-Windows-Hyper-V-Worker` montre l'activité VTL1. Sur Win11 24H2, `Microsoft-Windows-Security-Mitigations/KernelMode` inclut le cycle de vie d'enclave. Chasse pratique : lister les processus détenant le droit `SeEnableVirtualizationPrivilege`, recouper avec la présence d'un répertoire `IMAGE_ENCLAVE_CONFIG` dans leurs modules chargés, et alerter sur tout ce qui n'est **pas** `lsass.exe`, `LsaIso.exe`, pairs de `securekernel.exe`, ou trustlets Microsoft connus. Les éditeurs EDR *ne voient pas* l'exécution interne à l'enclave, mais ils voient la séquence syscall `NtCreateEnclave` / `NtLoadEnclaveData` / `NtInitializeEnclave` du processus hôte — hooker cela (ou récupérer l'ETW kernel-syscall) et traiter la chaîne comme un signal haute fidélité hors `lsass`. Defender utilise la couche HVCI pour refuser les images d'enclave non signées ; ne jamais désactiver HVCI dans un environnement managé.

Exemples de syscalls directs

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) }
}

Mappings MITRE ATT&CK

Last verified: 2026-05-20