> Windows Syscalls
ntoskrnl.exeT1055T1106T1070

NtDeleteAtom

Decrementa el contador de referencias de un átomo global y lo elimina cuando el contador llega a cero.

Prototipo

NTSTATUS NtDeleteAtom(
  RTL_ATOM Atom
);

Argumentos

NameTypeDirDescription
AtomRTL_ATOMinID de átomo de 16 bits devuelto por NtAddAtom / NtFindAtom. Debe estar en el rango usuario 0xC000-0xFFFF para átomos globales de usuario.

IDs de syscalls por versión de Windows

Versión de WindowsID de syscallBuild
Win10 15070xC1win10-1507
Win10 16070xC4win10-1607
Win10 17030xC7win10-1703
Win10 17090xC8win10-1709
Win10 18030xC9win10-1803
Win10 18090xCAwin10-1809
Win10 19030xCBwin10-1903
Win10 19090xCBwin10-1909
Win10 20040xCFwin10-2004
Win10 20H20xCFwin10-20h2
Win10 21H10xCFwin10-21h1
Win10 21H20xD0win10-21h2
Win10 22H20xD0win10-22h2
Win11 21H20xD5win11-21h2
Win11 22H20xD6win11-22h2
Win11 23H20xD6win11-23h2
Win11 24H20xD8win11-24h2
Server 20160xC4winserver-2016
Server 20190xCAwinserver-2019
Server 20220xD4winserver-2022
Server 20250xD8winserver-2025

Módulo del kernel

ntoskrnl.exeNtDeleteAtom

APIs relacionadas

DeleteAtomGlobalDeleteAtomNtAddAtomNtFindAtomNtQueryInformationAtom

Stub del syscall

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

El espejo de `NtAddAtom`. Cada AddAtom exitoso sobre un nombre existente incrementa un refcount; DeleteAtom lo decrementa. El átomo solo se retira físicamente de la tabla global cuando el contador llega a cero. Los wrappers Win32 `GlobalDeleteAtom` y `DeleteAtom` rutean por aquí. No hay contabilidad por proceso — cualquier proceso que conozca el ID puede decrementar el contador, lo que es a la vez la conveniencia de la API y el peligro de limpieza. Devuelve STATUS_INVALID_HANDLE para un ID fuera del rango usuario o un átomo nunca añadido.

Uso común por malware

**Limpieza de Atom Bombing**: el PoC original de enSilo (Tal Liberman 2016) y la adaptación Dridex 2017 invocan NtDeleteAtom sobre los IDs de átomos del shellcode contrabandeado después de que la APC objetivo haya copiado los bytes al espacio de direcciones de la víctima. Saltar la limpieza deja los bytes de shellcode en la tabla de átomos global para siempre (bueno, hasta el reboot) — un regalo forense para cualquier analista que lance `!atom` en WinDbg sobre una máquina viva, o que difere la tabla de átomos antes y después de una inyección sospechada. Fuera de la limpieza Atom Bomb la señal es esencialmente nula — `NtDeleteAtom` se dispara millones de veces al día por apps legítimas que registran y destruyen clases de ventana, topics DDE y cadenas IME.

Oportunidades de detección

Por sí solo, NtDeleteAtom es uno de los syscalls más ruidosos en un desktop Windows — Explorer, toda app WPF/WinForms, la stack de entrada, DWM, agitan constantemente la tabla de átomos. El pivot de detección es `NtAddAtom` con nombres anómalos (largos, binarios); si alertas sobre tráfico AddAtom sospechoso, el DeleteAtom correspondiente viene gratis en el mismo flujo. La extensión WinDbg `!atom` puede ser scripteada vía LiveKD / lkd para snapshottear periódicamente la tabla global y diferir entradas cuyos nombres no sean UTF-16 válido o cuya longitud en bytes exceda el típico tamaño de 32 bytes de una clase de ventana — esos son residuales de Atom Bomb. ETW Microsoft-Windows-Kernel-Audit-API-Calls cubre la llamada pero a muy alto volumen.

Ejemplos de syscalls directos

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtDeleteAtom (SSN 0xD8 on Win11 24H2)
NtDeleteAtom PROC
    mov  r10, rcx          ; syscall convention
    mov  eax, 0D8h         ; SSN — varies per build
    syscall
    ret
NtDeleteAtom ENDP

cAtom Bombing cleanup pass

// After NtQueueApcThread has delivered the GlobalGetAtomName APC into the
// target and the shellcode bytes have landed in the victim's buffer,
// scrub the smuggled atom IDs from the global table.
#include <windows.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI *pNtDeleteAtom)(USHORT);

VOID AtomBombCleanup(const USHORT* ids, ULONG count) {
    pNtDeleteAtom NtDeleteAtom = (pNtDeleteAtom)
        GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtDeleteAtom");
    for (ULONG i = 0; i < count; ++i) {
        // Refcount may be >1 if the OS interned the same string elsewhere
        // — call until the kernel returns STATUS_INVALID_HANDLE.
        while (NtDeleteAtom(ids[i]) == 0) { /* loop */ }
    }
}

rustBenign teardown via Win32 wrapper

// Cargo: windows-sys = "0.59" (Win32_System_DataExchange)
// Symmetric DeleteAtom for a string we registered with GlobalAddAtomW.
use windows_sys::Win32::System::DataExchange::GlobalDeleteAtom;

pub unsafe fn drop_atom(id: u16) {
    // Returns 0 on success — refcount hit zero.
    let _residual = GlobalDeleteAtom(id);
}

Mapeos MITRE ATT&CK

Last verified: 2026-05-20