The User-Mode to Kernel-Mode communication tends to be related to security, and the User-Mode components tends to be related to creating logon sessions for the user. The terms Client and Server are used here, and this tends to refer to a different thread or different process. It depends on who created the port and who is receiving the messages. LPCs build upon the concept of IPC (Inter-Process Communication):
Methods of IPC:
The methods are usually some form of synchronization like a Semaphore, or a shared object such as a File object or Memory-Mapped File. A comprehensive list can be found on Wikipedia.
Port Creation and Port API:
With Windows Vista onwards, the LPCs have been changed to ALPCs but as far as I'm aware they still have the same structures and can still be debugged in the same way. I've taken a list of the APIs from the MSDN blog to save writing the same information:
The messages are less than 256 bytes according to Microsoft. The messages (LPC/ALPC) are sent between the client and server. Each named port has a Security Descriptor and is able to check if it wishes to accept a connection request from a client by checking the CLIENT_ID.
Once the Server has successfully created a named connection port with NtCreatePort, then a Client may wish to establish a connection with the connection port, whereby the Server may check the CLIENT_ID, and if it is accepted (NtAcceptConnectPort) then two new ports will be created. These ports are the Server Communication Port and the Client Communication Port. A handle will be created to the Server Communication Port and given to the Server, and a handle will be created for the Client Communication Port and given to the Client, these ports are used to send and receive messages. The Server Communication Port can terminate the connection.
Now let's examine the Port Object data structure which is used to represent a type of port with server process and owning process. Using the _LPCP_PORT_OBJECT which can we can view using WinDbg and a Kernel Memory Dump. This is allocated from paged pool.
The ConnectionPort is a pointer to a similar data structure which is used to represent the Server Connection Port, and the ConnectedPort is used to represent the Server Communication Port.
The ClientThread is the Client's thread, and the ServerProcess is the Server's process. The LpcReplyChainHead is a doubly linked list of all the threads which are currently waiting for a reply from a sent message to that particular communication port.
The MsgQueue contains another data structure and a few additional fields of interest:
The Sempahore is used as a signal to show that messages are waiting within the doubly linked list which is the RecieveHead field.
The ReceiveHead as stated before is a doubly linked list containing all the messages which need to be dequeued by the server.
The NonPagedPortQueue is related to the Client Communication Port and is used to track any lost replies from the Server. The fields seem to similar to the general port queue.
The next important data structure is the _LPCP_MESSAGE structure which is allocated with paged pool, and used to track message related information between the Server and Client. This information includes Message Type, Message ID and the ClientID. We can also search through paged pool using the pool tag which is LpcM. ALPCs may use the _KALPC_MESSAGE data structure instead which contains similar information.
Here's the data structure for the message:
The SenderPort field is the Client Communication Port. It should have a Port Object data structure associated with it.
The RepliedToThread is the Client Thread which has been replied to. The Entry field is the entry within the doubly linked list associated with the Message Queue.
The Request field is a copy of message buffer passed as a parameter with the NtRequestWaitReplyPort. The _PORT_MESSAGE data structure contains a few additional fields.
The MessageId field is a unique message identifier. The CallbackId is the the Sender ID or related to the Sender. The ClientViewSize is the size of the section created by the sender, when using Memory Mapped Files, this applies when using the NtCreateSection/CreateFileMapping and thus _PORT_VIEW data structure.
The DataLength and the TotalLength fields are associated with the length of the data within the message and the header, and the TotalLength includes the size of the _PORT_MESSAGE structure.
We can check the _EPROCESS and _ETHREAD fields for information related to LPCs.
Let's begin with the _EPROCESS data structure which contains three LPC ports, which each have their own function within the Windows operating system:
The DebugPort is used for sending debugging messages (User-Mode), the ExceptionPort is used with CsrCreateProcess and used to create a new process with a connection with the debugging port. _LPC_EXCEPTION message is sent using this port when a thread doesn't catch a exception. The SecurityPort is used by the lasass.exe process for security purposes.
Using the -y switch to set some search query parameter, we need to search the _ETHREAD data structure for some LPC fields. On Windows Vista and later systems, some of the fields seems to have been removed. Windows XP will have the original LPC fields.
AlpcMessageId is the message sent to the Server while the Client Thread waits for a response. The AlpcMessage is a pointer to the message data structure seen earlier or I assume it to be. The AlpcWaitListEntry is a list of threads waiting for a reply from the Server communication or connection port depends upon the situation. The AlpcWaitSempahore causes a Client Thread to wait while the Server processes the message received.
The original Windows XP fields are described in the table below:
WinDbg Debugger Extensions:
The ALPC extensions do not seem to be documented within the WinDbg documentation, but the !lpc debugger extensions are documented. !lpc only applies to Windows XP and earlier. Windows Vista onwards will need to use the ALPC extensions which are limited in comparison.
I'm using the !alpc version of the debugger extension, but the !lpc extension seems to have more functionality such as the PoolSearch option, but you could try it with the !poolfind extension and the pooltag.
I've just chosen a random process, and then passed it as a parameter to the !alpc /lpp debugger extension to view which ports the process is connected to, and which ports were created by the process.
The address next to the process name appears to be the Process Address, and the first address (85eb9378) seems to be the Client Communication Port address, and the second address seems to be the address of the ApiPort. The !alpc /p extension helps to clarify this information. The 38 on the last line indicates the number of messages within the pending queue.
We can view message information with the !alpc /m extension:
The !lpc debugger extension documentation can be found in WinDbg, the !alpc extensions didn't have information, and therefore my assumptions on the fields were through investigation and knowledge from Microsoft related resources which will be added to the References section.
Common Issues:
By doing some research, I've manged to find some information on the common issues related to LPCs.
- Servers aren't able to send messages for Clients which are waiting for a LPC Message.
- There is no Timeout for LPC Wait APIs (this may have changed).
- If the Server Process is terminated, then the Client Threads aren't notified unless there were Client Threads waiting for a reply from that Server Process.
- The Server replied to the wrong Client, and the Server threads are completely deadlocked and thus can't process any more requests from Clients to a particular port.
References:
LPC Communication
No comments:
Post a Comment