> Windows Syscalls
ntoskrnl.exeT1620T1574T1106

NtLoadEnclaveData

Copie un buffer aligné page (code ou données) depuis la mémoire hôte VTL0 vers la plage VTL1 d'une enclave avant initialisation.

Prototype

NTSTATUS NtLoadEnclaveData(
  HANDLE  ProcessHandle,
  PVOID   BaseAddress,
  PVOID   Buffer,
  SIZE_T  BufferSize,
  ULONG   Protect,
  PVOID   PageInformation,
  ULONG   PageInformationLength,
  PSIZE_T NumberOfBytesWritten,
  PULONG  EnclaveError
);

Arguments

NameTypeDirDescription
ProcessHandleHANDLEinHandle vers le processus hôte propriétaire de l'enclave. Typiquement NtCurrentProcess().
BaseAddressPVOIDinAdresse VTL1 cible dans l'enclave où Buffer est copié. Doit être alignée page et dans la plage réservée de l'enclave.
BufferPVOIDinBuffer source VTL0 (image d'enclave mappée ou page de données). Aligné page.
BufferSizeSIZE_TinNombre d'octets à copier. Doit être un multiple de la taille de page.
ProtectULONGinProtection finale des pages dans l'enclave (PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE_READ — jamais WRITE+EXECUTE en VBS).
PageInformationPVOIDinDescripteur spécifique au type : ENCLAVE_LOAD_DATA_SGX (SECINFO + flags EADD) ou ENCLAVE_LOAD_DATA_VBS (type de page).
PageInformationLengthULONGinTaille en octets du descripteur PageInformation.
NumberOfBytesWrittenPSIZE_ToutReçoit le nombre d'octets réellement écrits dans l'enclave (normalement égal à BufferSize en succès).
EnclaveErrorPULONGoutReçoit le code d'erreur SGX EADD ou securekernel sur STATUS_ENCLAVE_FAILURE.

IDs de syscalls par version de Windows

Version de WindowsID de syscallBuild
Win10 16070xFAwin10-1607
Win10 17030xFDwin10-1703
Win10 17090xFEwin10-1709
Win10 18030xFFwin10-1803
Win10 18090x100win10-1809
Win10 19030x101win10-1903
Win10 19090x101win10-1909
Win10 20040x106win10-2004
Win10 20H20x106win10-20h2
Win10 21H10x106win10-21h1
Win10 21H20x107win10-21h2
Win10 22H20x107win10-22h2
Win11 21H20x10Cwin11-21h2
Win11 22H20x10Dwin11-22h2
Win11 23H20x10Dwin11-23h2
Win11 24H20x10Fwin11-24h2
Server 20160xFAwinserver-2016
Server 20190x100winserver-2019
Server 20220x10Bwinserver-2022
Server 20250x10Fwinserver-2025

Module noyau

ntoskrnl.exeNtLoadEnclaveData

APIs liées

LoadEnclaveDataLoadEnclaveImageWNtCreateEnclaveNtInitializeEnclaveNtCallEnclave

Stub du syscall

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

`NtLoadEnclaveData` est l'appel d'**ingestion page-par-page** qui tourne *entre* `NtCreateEnclave` et `NtInitializeEnclave`. Sur SGX il se transforme en `EADD` pour chaque page source ; sur VBS le Secure Kernel `IumLoadEnclaveData` copie le buffer source à travers la frontière VTL et estampille la mesure de la page destination dans le hash courant de l'enclave. La protection passée ici est la protection *finale* — l'enclave ne peut plus la remapper plus tard (aucun `mprotect` par page n'existe en VTL1). Pour une DLL d'enclave, `vertdll.dll` fait un appel par section `IMAGE_SCN_*` : un PAGE_READONLY pour `.rdata`, un PAGE_EXECUTE_READ pour `.text`, un PAGE_READWRITE pour `.data`. Tous les loads doivent précéder `NtInitializeEnclave` ; après, l'appel retourne `STATUS_ENCLAVE_NOT_TERMINATED`.

Usage courant par les malwares

Côté offensif, c'est l'appel qui *place physiquement du code en VTL1*. La barrière à l'abus est que les octets chargés seront mesurés dans le hash d'enclave et ce hash doit correspondre à ce que `IMAGE_ENCLAVE_CONFIG` permet à l'init. Deux leviers réels : (1) **enclave signée Microsoft avec données contrôlées par l'attaquant** : charger des pages de données bénignes dont le contenu est interprété comme des commandes par le code signé — équivalent à du ROP dans l'enclave ; (2) **loader de recherche** : les travaux Yuste / Soriano-Salvador chargent un *stub* d'enclave signé dont le 'code' est en fait un mini-dispatcher acceptant un pointeur shellcode au moment de `NtCallEnclave` — le payload malveillant n'est jamais mesuré dans MRENCLAVE, seul le dispatcher l'est. Les défenseurs ne peuvent pas inspecter les octets chargés a posteriori — la mémoire VTL1 est opaque à VTL0.

Opportunités de détection

Le burst de loads pré-init est très caractéristique : dizaines à centaines d'appels `NtLoadEnclaveData` rapprochés sur la même base d'enclave, suivis d'`NtInitializeEnclave`. Le provider ETW `Microsoft-Windows-Kernel-Memory` émet un event par load. Les EDR qui hookent le pattern syscall côté hôte peuvent flaguer la séquence trivialement ; le problème dur est l'attribution — quelle DLL est chargée dans l'enclave. Le meilleur levier défenseur est la *source fichier* : le module hôte qui effectue les loads aura un répertoire `IMAGE_ENCLAVE_CONFIG` nommant la DLL d'enclave par hash d'image. Sysmon Event ID 7 (ImageLoad) côté hôte montrera le mapping PE de la DLL d'enclave avant les syscalls de load — coupler les deux pour identification rétroactive.

Exemples de syscalls directs

cVBS enclave bring-up (step 2/3 — load image)

// Walk the PE sections of a signed enclave DLL and copy them into the enclave.
// (Helper for the create -> load -> initialize -> call sequence.)
#include <windows.h>

BOOL LoadEnclaveImage(PVOID enclaveBase, PVOID peImage, SIZE_T peSize) {
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)peImage;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)peImage + dos->e_lfanew);
    PIMAGE_SECTION_HEADER sec = IMAGE_FIRST_SECTION(nt);

    for (WORD i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++) {
        ULONG prot = PAGE_READONLY;
        if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) prot = PAGE_EXECUTE_READ;
        else if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) prot = PAGE_READWRITE;

        PVOID dst = (BYTE*)enclaveBase + sec->VirtualAddress;
        PVOID src = (BYTE*)peImage      + sec->PointerToRawData;
        SIZE_T size = ((sec->SizeOfRawData + 0xFFF) & ~0xFFFu);

        if (!LoadEnclaveData(
                GetCurrentProcess(),
                dst, src, size, prot,
                NULL, 0,           // page info (VBS-specific, may be NULL)
                NULL,              // bytes written
                NULL)) {           // enclave error
            return FALSE;
        }
    }
    return TRUE;
}

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtLoadEnclaveData (SSN 0x10F on Win11 24H2 / Server 2025)
NtLoadEnclaveData PROC
    mov  r10, rcx          ; ProcessHandle
    mov  eax, 10Fh         ; SSN
    syscall
    ret
NtLoadEnclaveData ENDP

Mappings MITRE ATT&CK

Last verified: 2026-05-20