ALPC monitoring

Microsoft did nice work related to callback mechanism, to avoid nasty patching across kernel, and support monitoring in clean way. Currently we can use, among others, for example callbacks on loading new image, process, thread, opening & duplicating handles, dropping files etc. For monitoring network communication you can attach to some device drivers, which is cleaner than hooking, but still does not cover as much as i want to. And there comes ALPC, because even resolving host comes through, and when you are able to recognize it ..


In april I attend awesome training at Syscan, training was led by Alex Ionescu. Among a lot of deep kernel stuffs, there was deeply covered ALPC mechanism, which is the point of this blog – post. Nice presentation about ALPC, which I really recommend to read : All about the RPC, LRPC, ALPC, and LPC in your PC 

starting with little windbg script :

.. that shows one interesting thing about ALPC, which I like at most :

-> everyone like ALPC. And especially applications with network communication, because as was said at training, even gethostbyname ends up by calling some ALPC! So I think it is really good point to start at some object responsible for communication

And because nt!_ALPC_PORT is of nt!_OBJECT_TYPE it give us opportunity to attach to it by ObFiltering, and it seems it is really possible :

But same time filtering objects come with some limitations!


OB_OPERATION_HANDLE_CREATE – A new process handle or thread handle was or will be opened.

OB_OPERATION_HANDLE_DUPLICATE – A process handle or thread handle was or will be duplicated.

Thats basically means, that we are theoretically able to get called at two mentioned HANDLE operations. Thats good, but wants to get more .. after some digging of nt!_ALPC_PORT it is possible to spot nice structure :

So lets take a look at some subset of nt function responsible for playing with alpc :

One good candidate to deeper look is NtAlpcSetInformation which call AlpcpInitializeCompletionList and it ends by calling IoAllocateMiniCompletionPacket – and this last routine can sound pretty familiar now!

OK, but whats happening there ? It is another callback mechanism – *CompletionIo*, already described in Windows internals 6th edition, Part2 (I/O Completion Ports). And this callback mechanism is setup-ed by default as you have already seen to call nt!AlpcpLookasidePacketCallbackRoutine.

It is obvious that it is possible to intercept mechanism by rewriting this callback, but this is not what we want to do … When we look at this default function, we can see how this callback  mechanism work.

nt!IoSetIoCompletionEx2 ends in nt!IoSetIoCompletionEx, and  nt!AlpcpDeferredFreeCompletionPacketLookaside ends by calling nt!IoFreeMiniCompletionPacket per packet in queue.

  • init : nt!IoAllocateMiniCompletionPacket
  • registering : nt!IoSetIoCompletionEx
  • free : nt!IoFreeMiniCompletionPacket

and now how to setup own Callback packet :


So now almost done, but one essential thing is missing – alpc port itself to attach .. and there exist some approaches how to find it :

  1. !alpc /lpp

    kdexts.dll do it somehow, so here is the approach :

    … unfortunately nt!AlpcpPortList is not exported symbol, but its location is inside this ‘structure’ :

    one member of this structure which can be found quite easly is nt!AlpcPortObjectType, which is not directly exported, but fortunately for us nt!LpcPortObjectType is alias to it!
    And there is also another way to get it (not so comfortable) – querying it :

    to successfully locate this structure, and port list itself, inside of ntoskrnl image just add additional checks of predicable values of some members of structure alongside with equality of value for nt!AlpcPortObjectType

  2. ObFiltering

    Another option *should* be an official option, but in reallity …

    Ob Filters, and registering on nt!AlpcPortObjectType, mechanism is ready to use and it is already implemented in kernel! But you have some obstacles :

    • nt!AlpcPortObjectType vs ObjectTypes

    a lot of object to query for, what are the object types of theirs ?

    and how many are officialy supported and exported for kernel dev ?

    nt!AlpcPortObjectType is not between exported ones .. but still no such big deal, we can query it by object dir, as we already did in first approach.

    • nt!_OBJECT_TYPE vs “ALPC Port”


    ehmm, callbacks disabled, but still we can patch it (as others up to win7 already did)

    • PatchGuard from win8.1

    no you can not patch it anymore!

How To

Ok, so no Ob filtering on “ALPC Port” is NOT allowed, yet! But still you know for what you looking for, so you can do it anyway, by walking trough list in appropriate moments and using first method

And you can be even more specific while monitoring, because that communication with svchost, or other generic service, is not information bomb at all, but you can look at it through service names, which can be useful far more!

Article about resolving service name by its id (SubProcessTag) you can find here, and also is written more concrete example of implementation here, and even more you can find it in process hacker as well. This method was designed for user mode, but in kernel you are by creation, so lets say it is more straighforward to resolve this information


btw. in your IoCompletition alpc callback, your minipacket contains KeyContext which looks like :


Conclusions :

Seems that IoCompletion callbacks can be really helpful mechanism. It works just on ports that use the I/O completion port type, not on all ALPC ports, but for network monitoring purposes seems it is fair enough :) 

Another limitation is that ‘limited’ usage of Ob Filters on AlpcPorts. It is quite nice feature but limited so much …  I hope filtering will support at least nt!AlpcPortObjectType soon!

At the end of this post, I would like to thank to Alex Ionescu for reviewing this article, and for that nice syscan win-internals training!


Leave a comment


Leave a Reply

[ Ctrl + Enter ]

Go To Top

Get every new post delivered to your Inbox

Join other followers: