The Advanced (or Asynchronous if you prefer) Local Procedure Calls (ALPC) is the internal communication mechanism Windows components use as an inter-process communication (IPC) mechanism for message exchange. Conceptually, it’s similar in principle to Remote Procedure Calls (RPC), with client and server ports, but does not use any networking, and is optimized for different message sizes.
ALPC messages can reveal the hidden communication between various processes that are almost invisible otherwise. Conceptually, hooking ALPC messages is possible but not easy. First, the user mode and kernel mode APIs are undocumented. Second, hooking would likely involve all processes for which ALPC would be interesting, including protected processes (such as CSRSS) that cannot be hooked from user mode. And finally, hooking is inherently dangerous and complex; it’s best avoided unless there is no other choice.
Fortunately, there is a choice that can be quite useful in many scenarios that gives enough information so as to make the idea of hooking unappealing. ALPC provides notifications via Event Tracing for Windows (ETW) that can be captured by ETW consumers.
Let’s consider a concrete example. Suppose we want to build a sandbox around a process, say a web browser, so that it would not be possible (or at least detectable) for that process to spawn potentially dangerous processes, such as powershell.exe, cmd.exe and rundll32.exe. One way to achieve that is by creating a kernel mode driver that registers for process creation and termination notifications (PsSetCreateProcessNotifyRoutineEx) and looking at the to-be-created process and its parent process. If the process to create is one of the forbidden and the creator is our sandbox-targeted process (the web browser in this example), we can simply disallow process creation by setting a failure status code in the CreationStatus member of the passed in PS_CREATE_NOTIFY_INFO structure.
The problem with the above approach is that it has holes, because there are indirect ways to spawn new processes, such as with some out of process COM servers or WMI. The WMI example is a canonical example of this. A process can use WMI APIs to create a new process, which involves the WMI service hosted in a standard Svchost process, which will ask the WMI provider host process (WmiPrvSE) to do the actual work. So, in our driver we would see the final process created (e.g. cmd.exe), but its parent would be WmiPrvSE – not our web browser process, which means we have no easy way of knowing who really initiated the creation of cmd.exe. This is where ALPC comes in.
I’ve created a simple ALPC Logger application that monitors ALPC calls between all processes based on ETW. The current UI looks like the following:
The grid shows ALPC calls from a source process/thread to a target process/thread. I’ve used the great Microsoft.Diagnostics.Tracing.TraceEvent library (available through Nuget) that allows easy consumption of ETW events in .NET. Currently, a simple filter exists that allows filtering entries by process names; I intend to add more powerful filtering and a suitable GUI to set it up.
The Analysis menu contains a “Find Chains…” option that should show call chains involving several processes that are part of the same logical thread; this is still in development as I want to show it in a nice UI (the eager reader may fork and implement…). This is not always easy, as ALPC can be asynchronous, which means thread ID correlation would be difficult.
Let’s look at an example involving WMI. We’ll create a notepad process through WMI from powershell. Powershell is used here just because it’s easy to work with WMI from powershell. However, the same idea can be accomplished in C++ with the WMI COM API, or in .NET with the System.Management namespace or from Python, etc.
After launching the ALPC Logger tool and clicking the Run button to start logging, we enter the following in powershell:
Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad
This creates a notepad process through WMI. Stop the logging and set a filter to remove all “noise” to something like this:
The dashes remove any mention of the process names indicated, and what’s left is filtered by what to include. In this case, powershell and notepad. Clearly, finding the logical ALPC calls should be done by the tool, but for now we can try tracing calls from some source thread to a target (receiving) thread, and from that thread to yet another thread and so on. Frequently, we’ll find the source leads to the target which leads to the source. This would indicate a simple synchronous request-reply message. But, occasionally it will be more complex and involve a third process. This is what we’re after. The following screenshot shows some of the filtered results.
The highlighted line shows the communication between the WMI service to the WMI provider host. Note that as part of the ETW information, the call stack is also provided (addresses for stack frames), which, with proper symbols can be shown as well (a future feature I plan as well). The preceding calls show an interaction between the client process (powershell) to the WMI service. It’s not a definite proof – there are other services inside the same host – but some experimentation can reveal a pattern. Also, notice the message ID being the same in the interaction, hinting at some related activities.
To get definite proof that this is indeed process creation, we can use the stack trace (as mentioned) as collaboration and of course other telemetry such as the driver mentioned and even other ETW events (process and thread creation being some of them, removing the need for a driver of process creation prevention is not required).
This is certainly the tip of the iceberg for the usefulness of ETW in general and ALPC in particular.