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
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle vers le processus hôte. NtCurrentProcess() ((HANDLE)-1) est la seule valeur pratique. |
| BaseAddress | PVOID* | in/out | Pointeur vers la base demandée. NULL laisse le noyau choisir. Reçoit la base retenue en cas de succès. |
| ZeroBits | ULONG_PTR | in | Nombre de bits de poids fort à zéro dans BaseAddress. Typiquement 0. |
| Size | SIZE_T | in | Taille totale de la plage d'adresses de l'enclave en octets. Doit être une puissance de deux sur SGX ; aligné page sur VBS. |
| InitialCommitment | SIZE_T | in | Octets initialement validés ; le reste est réservé. 0 pour uniquement réserver. |
| EnclaveType | ULONG | in | ENCLAVE_TYPE_SGX (1), ENCLAVE_TYPE_SGX2 (2) ou ENCLAVE_TYPE_VBS (0x10). SGX déprécié depuis 2024. |
| EnclaveInformation | PVOID | in | Structure de création spécifique au type : ENCLAVE_CREATE_INFO_SGX ou ENCLAVE_CREATE_INFO_VBS (owner ID + flags). |
| EnclaveInformationLength | ULONG | in | Taille en octets de EnclaveInformation. |
| EnclaveError | PSIZE_T | out | Reçoit le code d'erreur matériel / securekernel quand NTSTATUS vaut STATUS_ENCLAVE_FAILURE. |
IDs de syscalls par version de Windows
| Version de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1607 | 0x9E | win10-1607 |
| Win10 1703 | 0xA1 | win10-1703 |
| Win10 1709 | 0xA2 | win10-1709 |
| Win10 1803 | 0xA3 | win10-1803 |
| Win10 1809 | 0xA3 | win10-1809 |
| Win10 1903 | 0xA4 | win10-1903 |
| Win10 1909 | 0xA4 | win10-1909 |
| Win10 2004 | 0xA8 | win10-2004 |
| Win10 20H2 | 0xA8 | win10-20h2 |
| Win10 21H1 | 0xA8 | win10-21h1 |
| Win10 21H2 | 0xA9 | win10-21h2 |
| Win10 22H2 | 0xA9 | win10-22h2 |
| Win11 21H2 | 0xAB | win11-21h2 |
| Win11 22H2 | 0xAC | win11-22h2 |
| Win11 23H2 | 0xAC | win11-23h2 |
| Win11 24H2 | 0xAE | win11-24h2 |
| Server 2016 | 0x9E | winserver-2016 |
| Server 2019 | 0xA3 | winserver-2019 |
| Server 2022 | 0xAB | winserver-2022 |
| Server 2025 | 0xAE | winserver-2025 |
Module noyau
APIs liées
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 ENDPrustwindows-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