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
| Name | Type | Dir | Description |
|---|---|---|---|
| Atom | RTL_ATOM | in | ID 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 Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xC1 | win10-1507 |
| Win10 1607 | 0xC4 | win10-1607 |
| Win10 1703 | 0xC7 | win10-1703 |
| Win10 1709 | 0xC8 | win10-1709 |
| Win10 1803 | 0xC9 | win10-1803 |
| Win10 1809 | 0xCA | win10-1809 |
| Win10 1903 | 0xCB | win10-1903 |
| Win10 1909 | 0xCB | win10-1909 |
| Win10 2004 | 0xCF | win10-2004 |
| Win10 20H2 | 0xCF | win10-20h2 |
| Win10 21H1 | 0xCF | win10-21h1 |
| Win10 21H2 | 0xD0 | win10-21h2 |
| Win10 22H2 | 0xD0 | win10-22h2 |
| Win11 21H2 | 0xD5 | win11-21h2 |
| Win11 22H2 | 0xD6 | win11-22h2 |
| Win11 23H2 | 0xD6 | win11-23h2 |
| Win11 24H2 | 0xD8 | win11-24h2 |
| Server 2016 | 0xC4 | winserver-2016 |
| Server 2019 | 0xCA | winserver-2019 |
| Server 2022 | 0xD4 | winserver-2022 |
| Server 2025 | 0xD8 | winserver-2025 |
Módulo del kernel
APIs relacionadas
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 ENDPcAtom 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