> Windows Syscalls
ntoskrnl.exeT1559T1106

NtAlpcAcceptConnectPort

Server-side ALPC accept — completes a pending client connection request and returns a per-client communication port.

Prototype

NTSTATUS NtAlpcAcceptConnectPort(
  PHANDLE                  PortHandle,
  HANDLE                   ConnectionPortHandle,
  ULONG                    Flags,
  POBJECT_ATTRIBUTES       ObjectAttributes,
  PALPC_PORT_ATTRIBUTES    PortAttributes,
  PVOID                    PortContext,
  PPORT_MESSAGE            ConnectionRequest,
  PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes,
  BOOLEAN                  AcceptConnection
);

Arguments

NameTypeDirDescription
PortHandlePHANDLEoutReceives a handle to the new per-client communication port (or NULL if AcceptConnection is FALSE).
ConnectionPortHandleHANDLEinHandle to the server's listening connection port previously created with NtAlpcCreatePort.
FlagsULONGinALPC connection flags (ALPC_MSGFLG_SYNC_REQUEST, ALPC_PORFLG_*); typically 0.
ObjectAttributesPOBJECT_ATTRIBUTESinOptional object attributes for the new communication port; typically NULL.
PortAttributesPALPC_PORT_ATTRIBUTESinServer-side port attributes (max-message size, view size, security-QoS) governing this client's port.
PortContextPVOIDinOpaque context value the server later retrieves on every receive on this port — typically a pointer to a per-client struct.
ConnectionRequestPPORT_MESSAGEinThe original LPC_CONNECTION_REQUEST PORT_MESSAGE received from NtAlpcSendWaitReceivePort that triggered this accept.
ConnectionMessageAttributesPALPC_MESSAGE_ATTRIBUTESinMessage attributes (handle, security context, view) sent back to the client as the accept reply payload.
AcceptConnectionBOOLEANinTRUE to accept the connection (returns a port handle); FALSE to reject it (client receives STATUS_PORT_CONNECTION_REFUSED).

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x73win10-1507
Win10 16070x73win10-1607
Win10 17030x74win10-1703
Win10 17090x74win10-1709
Win10 18030x75win10-1803
Win10 18090x75win10-1809
Win10 19030x75win10-1903
Win10 19090x75win10-1909
Win10 20040x77win10-2004
Win10 20H20x77win10-20h2
Win10 21H10x77win10-21h1
Win10 21H20x77win10-21h2
Win10 22H20x77win10-22h2
Win11 21H20x77win11-21h2
Win11 22H20x77win11-22h2
Win11 23H20x77win11-23h2
Win11 24H20x79win11-24h2
Server 20160x73winserver-2016
Server 20190x75winserver-2019
Server 20220x77winserver-2022
Server 20250x79winserver-2025

Kernel module

ntoskrnl.exeNtAlpcAcceptConnectPort

Related APIs

NtAlpcCreatePortNtAlpcConnectPortNtAlpcSendWaitReceivePortNtAlpcDisconnectPortRpcServerListenRpcServerUseProtseqEpW

Syscall stub

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

`NtAlpcAcceptConnectPort` is the exact counterpart of `NtAlpcConnectPort`: the server side of the ALPC three-way handshake. The canonical pattern is `NtAlpcCreatePort` (bind/listen) → `NtAlpcSendWaitReceivePort` (recv `LPC_CONNECTION_REQUEST`) → `NtAlpcAcceptConnectPort` (accept or reject). A successful accept returns a per-client communication port; subsequent message traffic flows over that handle, not the connection port. Every Windows RPC service that exposes an `ncalrpc` endpoint runs this loop, almost always via the `RPCRT4!RpcServerListen` wrapper rather than calling the Nt routine directly. There is no public Win32 surface.

Common malware usage

On its own, calling `NtAlpcAcceptConnectPort` from malware is unusual — it implies the malware is *itself* hosting an ALPC server endpoint to coordinate with other components (loader ↔ injected DLL ↔ persistence service). Some long-form modular implants do exactly this because ALPC is invisible to Sysmon network telemetry and survives even when the host has no outbound network. More commonly, the syscall is interesting in the *reverse* direction: ALPC LPE exploit chains (CVE-2018-8440 Task Scheduler, multiple Print Spooler bugs) end up tricking a *privileged* server's accept loop into mishandling a forged connection-request `PORT_MESSAGE` — the bug is in the caller of `NtAlpcAcceptConnectPort`, not in the syscall.

Detection opportunities

Detection is asymmetric: this is dominated by every legitimate service on the box. The signal lives in *which* process is calling it. Running `handle.exe -a -p <pid>` (or equivalent) on a non-service / non-Microsoft binary and finding an `ALPC Port \RPC Control\…` server endpoint is anomalous. ETW `Microsoft-Windows-Kernel-ALPC` exposes per-port accept events but is rarely enabled at scale. SystemInformer's ALPC tab enumerates server ports per process and is the most useful post-incident discovery tool.

Direct syscall examples

asmx64 direct stub (Win11 24H2)

; Direct syscall stub for NtAlpcAcceptConnectPort (SSN 0x79 on Win11 24H2)
NtAlpcAcceptConnectPort PROC
    mov  r10, rcx          ; PortHandle
    mov  eax, 79h          ; SSN — drifts per build
    syscall
    ret
NtAlpcAcceptConnectPort ENDP

cMinimal ALPC server accept loop

// Skeleton of the canonical create → recv-connreq → accept loop.
#include <windows.h>
#include <winternl.h>

typedef NTSTATUS (NTAPI *pNtAlpcAcceptConnectPort)(
    PHANDLE, HANDLE, ULONG, POBJECT_ATTRIBUTES, PVOID,
    PVOID, PPORT_MESSAGE, PVOID, BOOLEAN);

static pNtAlpcAcceptConnectPort g_accept;

NTSTATUS HandleConnReq(HANDLE hConnectionPort,
                       PPORT_MESSAGE pConnReq) {
    HANDLE hClient = NULL;
    // Per-client context — survives across receives.
    PVOID ctx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 64);
    NTSTATUS st = g_accept(&hClient, hConnectionPort, 0,
                           NULL, NULL, ctx, pConnReq, NULL,
                           TRUE /* accept */);
    // hClient is now the per-client comm port — pump it with
    // NtAlpcSendWaitReceivePort in a worker thread.
    return st;
}

MITRE ATT&CK mappings

Last verified: 2026-05-20