> Windows Syscalls
ntoskrnl.exeT1106T1070

NtMakeTemporaryObject

Limpia el atributo OBJ_PERMANENT para que el objeto kernel se libere al cerrarse el último handle.

Prototipo

NTSTATUS NtMakeTemporaryObject(
  HANDLE Handle
);

Argumentos

NameTypeDirDescription
HandleHANDLEinHandle a un objeto kernel con nombre que actualmente lleva el atributo OBJ_PERMANENT.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070xFEwin10-1507
Win10 16070x103win10-1607
Win10 17030x107win10-1703
Win10 17090x108win10-1709
Win10 18030x109win10-1803
Win10 18090x109win10-1809
Win10 19030x10Awin10-1903
Win10 19090x10Awin10-1909
Win10 20040x10Fwin10-2004
Win10 20H20x10Fwin10-20h2
Win10 21H10x10Fwin10-21h1
Win10 21H20x110win10-21h2
Win10 22H20x110win10-22h2
Win11 21H20x116win11-21h2
Win11 22H20x117win11-22h2
Win11 23H20x117win11-23h2
Win11 24H20x119win11-24h2
Server 20160x103winserver-2016
Server 20190x109winserver-2019
Server 20220x115winserver-2022
Server 20250x119winserver-2025

Módulo del kernel

ntoskrnl.exeNtMakeTemporaryObject

APIs relacionadas

NtMakePermanentObjectNtCloseNtOpenSectionNtOpenEvent

Stub del syscall

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

Contraparte estricta de `NtMakePermanentObject`: llama `ObSetPermanentObject(object, FALSE)` y suelta la referencia extra que Ob retenía para mantener vivo el objeto más allá del handle-count cero. El acceso requerido en el handle es `DELETE`. *No requiere* `SeCreatePermanentPrivilege` — convertir un objeto permanente de vuelta a temporal es asimétrico en ese sentido. Una vez quitado, el kernel verifica si quedan handles o referencias; si no, el objeto entra inmediatamente en la cola de eliminación diferida. Usado mayormente por rutas de shutdown de servicio (p. ej. csrss desmontando objetos nombrados de alcance de sesión) y por Win32 mismo cuando `CloseHandle` es la última operación sobre lo que originalmente era un objeto `OBJ_PERMANENT` creado por un proceso ya saliente.

Uso común por malware

Señal de malware baja. Dos apariciones notables: (1) **utilidades de cleanup forense / EDR** lo llaman para recoger objetos permanentes rogue dejados por payloads previos — `WinObj` mismo usa esta ruta cuando haces click derecho en un objeto permanente y eliges Make Temporary, luego Close. (2) Algunos diseños de implante lo usan defensivamente para *destruir* sus propios objetos de staging antes de salir, negando al defensor la oportunidad de dumpearlos post-mortem — p. ej. una sección permanente sirvió para pasar un payload a un helper de integridad superior, el helper lo consumió, y luego el implante emite `NtMakeTemporaryObject` seguido de `NtClose` para asegurar que no quede residuo en `\BaseNamedObjects`. La llamada es por lo demás inerte.

Oportunidades de detección

Sin evento ETW dedicado. Revisar las *consecuencias* — desaparición de objetos nombrados esperados en `\BaseNamedObjects` — es más práctico que alertar sobre este syscall. Correlacionar eventos de cierre de handle de objeto kernel con el naming de objeto para detectar objetos nombrados que desaparecen antes de que su servicio dueño deba apagarse. El par `NtMakePermanentObject` (o creación con `OBJ_PERMANENT`) seguido de `NtMakeTemporaryObject` desde el mismo proceso en una ventana corta es el patrón canónico stage-IPC-luego-wipe.

Ejemplos de syscalls directos

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtMakeTemporaryObject (SSN 0x119 on Win11 24H2 / Server 2025)
NtMakeTemporaryObject PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 119h         ; SSN — drifts; resolve dynamically for portability
    syscall
    ret
NtMakeTemporaryObject ENDP

cForensic-style reap of a rogue permanent object

// Cleanup pattern: open a permanent named event/section/mutex with DELETE
// access, strip OBJ_PERMANENT, then drop our handle so it's freed.
UNICODE_STRING name; RtlInitUnicodeString(&name, L"\\BaseNamedObjects\\Global\\__rogue__");
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE h;
if (NT_SUCCESS(NtOpenEvent(&h, DELETE, &oa))) {
    NtMakeTemporaryObject(h);   // clear OBJ_PERMANENT
    NtClose(h);                  // last close -> object freed
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20