> Windows Syscalls
ntoskrnl.exeT1547.001T1546.012T1112

NtCreateKey

Crea o abre una clave del registro — la primitiva del kernel detrás de toda persistencia registrada.

Prototipo

NTSTATUS NtCreateKey(
  PHANDLE            KeyHandle,
  ACCESS_MASK        DesiredAccess,
  POBJECT_ATTRIBUTES ObjectAttributes,
  ULONG              TitleIndex,
  PUNICODE_STRING    Class,
  ULONG              CreateOptions,
  PULONG             Disposition
);

Argumentos

NameTypeDirDescription
KeyHandlePHANDLEoutRecibe el handle de la clave creada o abierta.
DesiredAccessACCESS_MASKinMáscara de acceso, p. ej. KEY_WRITE, KEY_ALL_ACCESS, KEY_SET_VALUE.
ObjectAttributesPOBJECT_ATTRIBUTESinOBJECT_ATTRIBUTES con la ruta del registro (p. ej. \Registry\Machine\Software\...).
TitleIndexULONGinReservado. Debe ser cero.
ClassPUNICODE_STRINGinNombre de clase opcional. Normalmente NULL.
CreateOptionsULONGinBanderas, p. ej. REG_OPTION_NON_VOLATILE, REG_OPTION_VOLATILE, REG_OPTION_CREATE_LINK.
DispositionPULONGoutRecibe REG_CREATED_NEW_KEY o REG_OPENED_EXISTING_KEY. Puede ser NULL.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070x1Dwin10-1507
Win10 16070x1Dwin10-1607
Win10 17030x1Dwin10-1703
Win10 17090x1Dwin10-1709
Win10 18030x1Dwin10-1803
Win10 18090x1Dwin10-1809
Win10 19030x1Dwin10-1903
Win10 19090x1Dwin10-1909
Win10 20040x1Dwin10-2004
Win10 20H20x1Dwin10-20h2
Win10 21H10x1Dwin10-21h1
Win10 21H20x1Dwin10-21h2
Win10 22H20x1Dwin10-22h2
Win11 21H20x1Dwin11-21h2
Win11 22H20x1Dwin11-22h2
Win11 23H20x1Dwin11-23h2
Win11 24H20x1Dwin11-24h2
Server 20160x1Dwinserver-2016
Server 20190x1Dwinserver-2019
Server 20220x1Dwinserver-2022
Server 20250x1Dwinserver-2025

Módulo del kernel

ntoskrnl.exeNtCreateKey

APIs relacionadas

RegCreateKeyExWRegOpenKeyExWNtOpenKeyNtOpenKeyExNtSetValueKeyNtDeleteKey

Stub del syscall

4C 8B D1            mov r10, rcx
B8 1D 00 00 00      mov eax, 0x1D
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

`0x1D` es el SSN desde Windows 7 y permanece sin cambios hasta Win11 24H2 — uno de los números más fiables para codificar en duro. La llamada pasa por CmpCallCallBacksEx y CmCreateKey en el Configuration Manager (asignación CM_KEY_BODY). Como la ruta de ObjectAttributes se analiza en el espacio de objetos NT (`\Registry\Machine\...`, `\Registry\User\<SID>\...`), los implantes la usan directamente para esquivar los hooks de traducción de ruta que los EDR colocan en advapi32!RegCreateKeyEx.

Uso común por malware

La persistencia es el uso dominante. Los operadores crean subclaves bajo `HKLM\Software\Microsoft\Windows\CurrentVersion\Run`, `HKCU\...\Run`, `HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon` (Shell/Userinit/AppInit_DLLs), `HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\<destino.exe>` (secuestro mediante valor Debugger), y `HKLM\System\CurrentControlSet\Services\<nombre>` para persistencia vía servicio. Llamar a NtCreateKey directamente evita los hooks de usuario en advapi32 y permite escribir sin dejar artefactos tipo CreateRemoteThread.

Oportunidades de detección

El proveedor ETW Microsoft-Windows-Kernel-Registry (`{70EB4F03-C1DE-4F73-A051-33D13D5413BD}`) dispara `EventCreateKey` (Opcode 10) con la ruta completa y el PID creador — la mejor fuente de detección y no es ocultable desde modo usuario. Sysmon Event ID 12 (RegistryEvent: CreateKey / DeleteKey) captura lo mismo donde no haya Defender for Endpoint. Cazar especialmente claves de autostart, subclaves IFEO sobre LOLBins comunes (`mmc.exe`, `taskmgr.exe`, `osk.exe`), y cualquier nueva entrada `Services\` cuyo ImagePath salga de `\SystemRoot\System32\`. Los hooks EDR de advapi32!RegCreateKeyEx se eluden fácilmente; el ETW del kernel no.

Ejemplos de syscalls directos

cCreate or open HKCU Run subkey

// Open / create HKCU\Software\Microsoft\Windows\CurrentVersion\Run via Nt path.
// Pair with NtSetValueKey to drop a persistence entry.
UNICODE_STRING path;
RtlInitUnicodeString(&path,
    L"\\Registry\\User\\<SID>\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");

OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);

HANDLE hKey = NULL;
ULONG disposition = 0;
NTSTATUS s = NtCreateKey(&hKey, KEY_SET_VALUE, &oa,
                        0, NULL, REG_OPTION_NON_VOLATILE, &disposition);

asmDirect stub (SSN 0x1D)

NtCreateKey PROC
    mov  r10, rcx
    mov  eax, 1Dh
    syscall
    ret
NtCreateKey ENDP

rustntapi crate persistence helper

// Cargo: ntapi = "0.4", winapi = { version = "0.3", features = ["winnt"] }
use ntapi::ntregapi::NtCreateKey;
use ntapi::ntrtl::RtlInitUnicodeString;
use winapi::shared::ntdef::{OBJECT_ATTRIBUTES, OBJ_CASE_INSENSITIVE, UNICODE_STRING};
use winapi::um::winnt::{KEY_SET_VALUE, REG_OPTION_NON_VOLATILE};
use std::ptr::null_mut;

pub unsafe fn open_run_key(sid_path: *const u16) -> *mut core::ffi::c_void {
    let mut us: UNICODE_STRING = core::mem::zeroed();
    RtlInitUnicodeString(&mut us, sid_path);
    let mut oa = OBJECT_ATTRIBUTES {
        Length: core::mem::size_of::<OBJECT_ATTRIBUTES>() as u32,
        RootDirectory: null_mut(),
        ObjectName: &mut us,
        Attributes: OBJ_CASE_INSENSITIVE,
        SecurityDescriptor: null_mut(),
        SecurityQualityOfService: null_mut(),
    };
    let mut h = null_mut();
    let mut disp = 0u32;
    NtCreateKey(&mut h, KEY_SET_VALUE, &mut oa, 0,
                null_mut(), REG_OPTION_NON_VOLATILE, &mut disp);
    h
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20