NtMakeTemporaryObject
Limpia el atributo OBJ_PERMANENT para que el objeto kernel se libere al cerrarse el último handle.
Prototipo
NTSTATUS NtMakeTemporaryObject( HANDLE Handle );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| Handle | HANDLE | in | Handle a un objeto kernel con nombre que actualmente lleva el atributo OBJ_PERMANENT. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xFE | win10-1507 |
| Win10 1607 | 0x103 | win10-1607 |
| Win10 1703 | 0x107 | win10-1703 |
| Win10 1709 | 0x108 | win10-1709 |
| Win10 1803 | 0x109 | win10-1803 |
| Win10 1809 | 0x109 | win10-1809 |
| Win10 1903 | 0x10A | win10-1903 |
| Win10 1909 | 0x10A | win10-1909 |
| Win10 2004 | 0x10F | win10-2004 |
| Win10 20H2 | 0x10F | win10-20h2 |
| Win10 21H1 | 0x10F | win10-21h1 |
| Win10 21H2 | 0x110 | win10-21h2 |
| Win10 22H2 | 0x110 | win10-22h2 |
| Win11 21H2 | 0x116 | win11-21h2 |
| Win11 22H2 | 0x117 | win11-22h2 |
| Win11 23H2 | 0x117 | win11-23h2 |
| Win11 24H2 | 0x119 | win11-24h2 |
| Server 2016 | 0x103 | winserver-2016 |
| Server 2019 | 0x109 | winserver-2019 |
| Server 2022 | 0x115 | winserver-2022 |
| Server 2025 | 0x119 | winserver-2025 |
Módulo del kernel
APIs relacionadas
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 ENDPcForensic-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