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
| Name | Type | Dir | Description |
|---|---|---|---|
| PortHandle | PHANDLE | out | Receives a handle to the new per-client communication port (or NULL if AcceptConnection is FALSE). |
| ConnectionPortHandle | HANDLE | in | Handle to the server's listening connection port previously created with NtAlpcCreatePort. |
| Flags | ULONG | in | ALPC connection flags (ALPC_MSGFLG_SYNC_REQUEST, ALPC_PORFLG_*); typically 0. |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | Optional object attributes for the new communication port; typically NULL. |
| PortAttributes | PALPC_PORT_ATTRIBUTES | in | Server-side port attributes (max-message size, view size, security-QoS) governing this client's port. |
| PortContext | PVOID | in | Opaque context value the server later retrieves on every receive on this port — typically a pointer to a per-client struct. |
| ConnectionRequest | PPORT_MESSAGE | in | The original LPC_CONNECTION_REQUEST PORT_MESSAGE received from NtAlpcSendWaitReceivePort that triggered this accept. |
| ConnectionMessageAttributes | PALPC_MESSAGE_ATTRIBUTES | in | Message attributes (handle, security context, view) sent back to the client as the accept reply payload. |
| AcceptConnection | BOOLEAN | in | TRUE to accept the connection (returns a port handle); FALSE to reject it (client receives STATUS_PORT_CONNECTION_REFUSED). |
Syscall IDs by Windows version
| Windows version | Syscall ID | Build |
|---|---|---|
| Win10 1507 | 0x73 | win10-1507 |
| Win10 1607 | 0x73 | win10-1607 |
| Win10 1703 | 0x74 | win10-1703 |
| Win10 1709 | 0x74 | win10-1709 |
| Win10 1803 | 0x75 | win10-1803 |
| Win10 1809 | 0x75 | win10-1809 |
| Win10 1903 | 0x75 | win10-1903 |
| Win10 1909 | 0x75 | win10-1909 |
| Win10 2004 | 0x77 | win10-2004 |
| Win10 20H2 | 0x77 | win10-20h2 |
| Win10 21H1 | 0x77 | win10-21h1 |
| Win10 21H2 | 0x77 | win10-21h2 |
| Win10 22H2 | 0x77 | win10-22h2 |
| Win11 21H2 | 0x77 | win11-21h2 |
| Win11 22H2 | 0x77 | win11-22h2 |
| Win11 23H2 | 0x77 | win11-23h2 |
| Win11 24H2 | 0x79 | win11-24h2 |
| Server 2016 | 0x73 | winserver-2016 |
| Server 2019 | 0x75 | winserver-2019 |
| Server 2022 | 0x77 | winserver-2022 |
| Server 2025 | 0x79 | winserver-2025 |
Kernel module
Related APIs
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 ENDPcMinimal 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