Level 3 · Chapter 4
ALPC & local RPC
The fast, asynchronous message fabric most same-machine Windows IPC actually runs on, underneath friendlier APIs.
RPC & COM foundations mentioned that ncalrpc, the local protocol sequence, typically rides on something underneath it. This chapter is about that something: ALPC (Advanced Local Procedure Call), the kernel-supported message-passing primitive that a great deal of same-machine Windows communication is quietly built on, from RPC itself down to core OS components like LSASS, CSRSS, and the SCM talking to their clients.
Plumbing, not a public API most developers touch
ALPC is deliberately not the interface application developers are meant to program against directly — RPC & COM foundations and, further up, COM, exist precisely so that developers get a friendlier, higher-level contract while ALPC handles the actual message transport underneath. This is the same layering principle running through the whole course: a lower-level mechanism optimized for performance and correctness, wrapped by a higher-level one optimized for usability, with most code never needing to know the lower layer exists.
Ports, not sockets
Where ALPC differs from something like TCP sockets is that it's built specifically for same-machine communication, which lets it skip an enormous amount of overhead a general-purpose network transport has to carry:
- Ports are the rendezvous objects — a server creates a port and listens on it; clients connect to it by name (or by a handle passed some other way).
- Messages are exchanged asynchronously, with the kernel handling delivery rather than the two sides having to coordinate blocking reads and writes directly.
- Handles and structured data can be passed directly as part of a message, something a network-oriented transport has no equivalent for, since a handle is only meaningful within a single machine's kernel object namespace in the first place.
- Security context travels with the connection. Because ALPC is entirely kernel-mediated, the kernel can attach caller identity to each message without needing a network-style authentication handshake — this is exactly what lets impersonation-style security checks (the same idea introduced in Named pipes) work efficiently for ALPC-based communication too.
Why this exists as a separate mechanism at all
Windows could, in principle, have made every local component talk over loopback network sockets, or over named pipes exclusively. ALPC exists because same-machine IPC has a fundamentally different cost profile than networked IPC, and core OS components — the ones on the critical path for essentially everything else, like CSRSS and LSASS — need that IPC to be as cheap as possible. A network-style transport carries overhead (packet framing, potential retransmission logic, generality for a hostile network) that's pure waste when both endpoints are guaranteed to be on the same kernel, and ALPC is built to strip exactly that overhead away.
A worked example: what "local RPC" is actually doing
When the Service Control Manager receives a start/stop request from sc.exe or Services.msc, the call travels as RPC using the ncalrpc protocol sequence — and that, underneath the RPC runtime's marshaling and stub-generation machinery, is an ALPC conversation between the calling process and services.exe. Nothing about the caller's code looks any different than if it were making a remote call over TCP; the actual transport choice and its performance characteristics are decided by the RPC runtime, using ALPC specifically because both processes happen to be on the same machine.
A common mistake
Because ALPC underlies so much important OS-internal communication, it's tempting to reach for it directly when writing application code that needs fast local IPC. Microsoft has never documented ALPC as a stable, supported application-level API — its message formats and behavior can change between Windows versions without notice, precisely because it's meant to be an implementation detail of RPC, COM, and specific OS components, not a public contract. Code that talks ALPC directly (rather than through RPC or another supported framework) is deliberately working below the documented API surface, and takes on the same fragility-across-versions risk described for Nt* calls in Ntdll & the user/kernel boundary.
Where this connects
- CSRSS, Win32k, and session UI plumbing is one of the original, and still active, consumers of this exact mechanism for session-level client/server communication.
- Access checks & the Security Reference Monitor is what actually evaluates the caller identity ALPC attaches to each message.