> Windows Syscalls
ntoskrnl.exeT1620T1574T1106

NtLoadEnclaveData

Copia un buffer alineado a página (código o datos) desde la memoria anfitrión VTL0 al rango VTL1 de la enclave antes de la inicialización.

Prototipo

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

Argumentos

NameTypeDirDescription
ProcessHandleHANDLEinHandle al proceso anfitrión propietario de la enclave. Típicamente NtCurrentProcess().
BaseAddressPVOIDinDirección VTL1 objetivo dentro de la enclave donde se copia Buffer. Debe estar alineada a página y dentro del rango reservado de la enclave.
BufferPVOIDinBuffer fuente VTL0 (la imagen de enclave mapeada o una página de datos). Alineado a página.
BufferSizeSIZE_TinNúmero de bytes a copiar. Debe ser un múltiplo del tamaño de página.
ProtectULONGinProtección final de las páginas dentro de la enclave (PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE_READ — nunca WRITE+EXECUTE en VBS).
PageInformationPVOIDinDescriptor específico del tipo: ENCLAVE_LOAD_DATA_SGX (SECINFO + flags EADD) o ENCLAVE_LOAD_DATA_VBS (tipo de página).
PageInformationLengthULONGinTamaño en bytes del descriptor PageInformation.
NumberOfBytesWrittenPSIZE_ToutRecibe el número de bytes realmente escritos en la enclave (normalmente igual a BufferSize en éxito).
EnclaveErrorPULONGoutRecibe el código de error SGX EADD o securekernel en STATUS_ENCLAVE_FAILURE.

IDs de syscalls por versión de Windows

Versión 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

Módulo del kernel

ntoskrnl.exeNtLoadEnclaveData

APIs relacionadas

LoadEnclaveDataLoadEnclaveImageWNtCreateEnclaveNtInitializeEnclaveNtCallEnclave

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

Notas no documentadas

`NtLoadEnclaveData` es la llamada de **ingesta página-a-página** que corre *entre* `NtCreateEnclave` y `NtInitializeEnclave`. En SGX se traduce en un `EADD` por cada página fuente; en VBS el Secure Kernel `IumLoadEnclaveData` copia el buffer fuente a través de la frontera VTL y estampa la medición de la página destino en el hash en curso de la enclave. La protección pasada aquí es la *final* — la enclave no puede remapearla luego (no existe `mprotect` por página en VTL1). Para una DLL de enclave, `vertdll.dll` hace una llamada por sección `IMAGE_SCN_*`: un PAGE_READONLY para `.rdata`, un PAGE_EXECUTE_READ para `.text`, un PAGE_READWRITE para `.data`. Todas las cargas deben preceder a `NtInitializeEnclave`; después la llamada devuelve `STATUS_ENCLAVE_NOT_TERMINATED`.

Uso común por malware

Desde el ángulo ofensivo, ésta es la llamada que *coloca físicamente código en VTL1*. La barrera al abuso es que los bytes cargados serán medidos en el hash de la enclave y ese hash debe coincidir con lo que permite `IMAGE_ENCLAVE_CONFIG` en el init. Dos palancas reales: (1) **enclave firmada por Microsoft con datos controlados por el atacante**: cargar páginas de datos benignas cuyo contenido es interpretado como comandos por el código firmado — equivale a ROP dentro de la enclave; (2) **loader de investigación**: el trabajo Yuste / Soriano-Salvador carga un *stub* de enclave firmado cuyo 'código' es realmente un mini-dispatcher que acepta un puntero a shellcode en `NtCallEnclave` — el payload malicioso nunca se mide en MRENCLAVE, sólo el dispatcher. Los defensores no pueden inspeccionar los bytes cargados a posteriori — la memoria VTL1 es opaca a VTL0.

Oportunidades de detección

El burst de loads previo al init es muy característico: decenas-a-centenas de `NtLoadEnclaveData` próximos en el tiempo sobre la misma base de enclave, seguidos de `NtInitializeEnclave`. El proveedor ETW `Microsoft-Windows-Kernel-Memory` emite un evento por load. Los EDR que hookean el patrón syscall del anfitrión pueden flaguear la secuencia trivialmente; lo difícil es la atribución — qué DLL se carga en la enclave. La mejor palanca defensora es la *fuente de archivo*: el módulo anfitrión que hace los loads tendrá un directorio `IMAGE_ENCLAVE_CONFIG` nombrando la DLL de enclave por hash de imagen. Sysmon Event ID 7 (ImageLoad) en el anfitrión mostrará el mapeo PE de la DLL de enclave antes de los syscalls de load — combinar ambos para identificación retroactiva.

Ejemplos de syscalls directos

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

Mapeos MITRE ATT&CK

Last verified: 2026-05-20