> Windows Syscalls
ntoskrnl.exeT1106T1027.011

NtRemoveIoCompletion

Dequeues a single completion packet from an I/O completion port, blocking until one is available or the timeout expires.

Prototype

NTSTATUS NtRemoveIoCompletion(
  HANDLE          IoCompletionHandle,
  PVOID          *KeyContext,
  PVOID          *ApcContext,
  PIO_STATUS_BLOCK IoStatusBlock,
  PLARGE_INTEGER  Timeout
);

Arguments

NameTypeDirDescription
IoCompletionHandleHANDLEinHandle to the completion port. Requires IO_COMPLETION_MODIFY_STATE.
KeyContextPVOID *outReceives the CompletionKey that the producer supplied to NtSetIoCompletion.
ApcContextPVOID *outReceives the ApcContext from the producer — typically the OVERLAPPED* tied to the original I/O.
IoStatusBlockPIO_STATUS_BLOCKoutReceives the Status and Information fields of the dequeued packet.
TimeoutPLARGE_INTEGERinRelative (negative) or absolute (positive) timeout in 100ns units. NULL waits forever.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x9win10-1507
Win10 16070x9win10-1607
Win10 17030x9win10-1703
Win10 17090x9win10-1709
Win10 18030x9win10-1803
Win10 18090x9win10-1809
Win10 19030x9win10-1903
Win10 19090x9win10-1909
Win10 20040x9win10-2004
Win10 20H20x9win10-20h2
Win10 21H10x9win10-21h1
Win10 21H20x9win10-21h2
Win10 22H20x9win10-22h2
Win11 21H20x9win11-21h2
Win11 22H20x9win11-22h2
Win11 23H20x9win11-23h2
Win11 24H20x9win11-24h2
Server 20160x9winserver-2016
Server 20190x9winserver-2019
Server 20220x9winserver-2022
Server 20250x9winserver-2025

Kernel module

ntoskrnl.exeNtRemoveIoCompletion

Related APIs

GetQueuedCompletionStatusGetQueuedCompletionStatusExNtRemoveIoCompletionExNtCreateIoCompletionNtSetIoCompletionNtWaitForWorkViaWorkerFactory

Syscall stub

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

Undocumented notes

Another extraordinarily stable syscall — `0x9` since Windows 7. NtRemoveIoCompletion is the kernel side of `GetQueuedCompletionStatus`. It pops a single packet from the port's KQUEUE; if the queue is empty it blocks the calling thread on the port's wait list until NtSetIoCompletion is called, a real I/O completes, or the timeout expires. The Win32 wrapper merely translates between the kernel's three-field return (KeyContext, ApcContext, IoStatusBlock) and the Win32 four-argument shape (numBytes, completionKey, lpOverlapped).

Common malware usage

Like NtCreateIoCompletion, this syscall is so ubiquitous in legitimate code that it has no standalone attack signature. PoolParty exploitation does not invoke it directly — the worker factory variants use NtWaitForWorkViaWorkerFactory instead, which is bound to the factory. NtRemoveIoCompletion appears in sleep-evasion gadgets that mimic a benign server's idle pattern (loop on NtRemoveIoCompletion with a long timeout, decrypt beacon when woken, encrypt again before going back to wait) and in some custom C2 transports that piggyback on overlapped sockets to bury their traffic in the noise of legitimate I/O.

Detection opportunities

Effectively undetectable in isolation. Behavioural analytics that correlate completion-port wait patterns with the *absence* of corresponding real I/O can flag sleep gadgets — a process that holds many threads in NtRemoveIoCompletion against a port that no one outside the process writes to is anomalous. ETW Microsoft-Windows-Kernel-IoCompletion can sample dequeue events at high cost. The most realistic detection vector is still upstream: catch the suspicious NtCreateIoCompletion/NtCreateWorkerFactory pair, then NtRemoveIoCompletion activity becomes secondary evidence.

Direct syscall examples

cStandard server loop

for (;;) {
    PVOID key = NULL, apc = NULL;
    IO_STATUS_BLOCK iosb;
    LARGE_INTEGER timeout; timeout.QuadPart = -10000000LL * 30; // 30s rel
    NTSTATUS s = NtRemoveIoCompletion(hIocp, &key, &apc, &iosb, &timeout);
    if (s == STATUS_TIMEOUT) continue;
    if (!NT_SUCCESS(s)) break;
    HandlePacket(key, (LPOVERLAPPED)apc, iosb.Status,
                 (DWORD)iosb.Information);
}

asmx64 direct stub (SSN 0x9)

; Stable across every Win10/Win11 build.
NtRemoveIoCompletion PROC
    mov  r10, rcx
    mov  eax, 9
    syscall
    ret
NtRemoveIoCompletion ENDP

rustSleep-evasion shaped wait

// Mimic a benign server's idle pattern. Real implants would also re-encrypt
// their RX region around the wait and timing-correlate with HTTP keep-alives.
use ntapi::ntioapi::{NtRemoveIoCompletion, IO_STATUS_BLOCK};
use winapi::shared::ntdef::LARGE_INTEGER;

unsafe fn napkin_sleep(h_iocp: windows_sys::Win32::Foundation::HANDLE, secs: i64) {
    let mut key: *mut core::ffi::c_void = core::ptr::null_mut();
    let mut apc: *mut core::ffi::c_void = core::ptr::null_mut();
    let mut iosb: IO_STATUS_BLOCK = core::mem::zeroed();
    let mut to: LARGE_INTEGER = core::mem::zeroed();
    *to.QuadPart_mut() = -10_000_000 * secs;
    let _ = NtRemoveIoCompletion(h_iocp, &mut key, &mut apc, &mut iosb, &mut to);
}

MITRE ATT&CK mappings

Last verified: 2026-05-20