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
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle al proceso anfitrión propietario de la enclave. Típicamente NtCurrentProcess(). |
| BaseAddress | PVOID | in | Direcció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. |
| Buffer | PVOID | in | Buffer fuente VTL0 (la imagen de enclave mapeada o una página de datos). Alineado a página. |
| BufferSize | SIZE_T | in | Número de bytes a copiar. Debe ser un múltiplo del tamaño de página. |
| Protect | ULONG | in | Protección final de las páginas dentro de la enclave (PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE_READ — nunca WRITE+EXECUTE en VBS). |
| PageInformation | PVOID | in | Descriptor específico del tipo: ENCLAVE_LOAD_DATA_SGX (SECINFO + flags EADD) o ENCLAVE_LOAD_DATA_VBS (tipo de página). |
| PageInformationLength | ULONG | in | Tamaño en bytes del descriptor PageInformation. |
| NumberOfBytesWritten | PSIZE_T | out | Recibe el número de bytes realmente escritos en la enclave (normalmente igual a BufferSize en éxito). |
| EnclaveError | PULONG | out | Recibe el código de error SGX EADD o securekernel en STATUS_ENCLAVE_FAILURE. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1607 | 0xFA | win10-1607 |
| Win10 1703 | 0xFD | win10-1703 |
| Win10 1709 | 0xFE | win10-1709 |
| Win10 1803 | 0xFF | win10-1803 |
| Win10 1809 | 0x100 | win10-1809 |
| Win10 1903 | 0x101 | win10-1903 |
| Win10 1909 | 0x101 | win10-1909 |
| Win10 2004 | 0x106 | win10-2004 |
| Win10 20H2 | 0x106 | win10-20h2 |
| Win10 21H1 | 0x106 | win10-21h1 |
| Win10 21H2 | 0x107 | win10-21h2 |
| Win10 22H2 | 0x107 | win10-22h2 |
| Win11 21H2 | 0x10C | win11-21h2 |
| Win11 22H2 | 0x10D | win11-22h2 |
| Win11 23H2 | 0x10D | win11-23h2 |
| Win11 24H2 | 0x10F | win11-24h2 |
| Server 2016 | 0xFA | winserver-2016 |
| Server 2019 | 0x100 | winserver-2019 |
| Server 2022 | 0x10B | winserver-2022 |
| Server 2025 | 0x10F | winserver-2025 |
Módulo del kernel
APIs relacionadas
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 ENDPMapeos MITRE ATT&CK
Last verified: 2026-05-20