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 :

alpc on system by windbg script r? @$t6 = (nt!_LIST_ENTRY*)@@(nt!PsActiveProcessHead) .for (r? @$t7 = @$t6->Flink; (@$t6 != @$t7); r? @$t7 = @$t7->Flink) { r? @$t8 = #CONTAINING_RECORD(@$t7, nt!_EPROCESS, ActiveProcessLinks) r? @$t0 = (nt!_LIST_ENTRY*)@@(nt!AlpcpPortList) .for (r? @$t1 = @$t0->Flink; (@$t0 != @$t1); r? @$t1 = @$t1->Flink) { r? @$t2 = #CONTAINING_RECORD(@$t1, nt!_ALPC_PORT, PortListEntry) .if (@@(@$t8) == @@(@$t2->OwnerProcess)) { .if @@(@$t2->CommunicationInfo->ConnectionPort) { .printf /D "<link cmd=\"!alpc /p @$t2\">Server Port Info</link> <-> "; .printf /D "<link cmd=\"!alpc /p @@(@$t2->CommunicationInfo->ConnectionPort)\">Connection Port Info</link> | "; .printf "%10ma (%0.4x) <- ", @@(@$t2->OwnerProcess->ImageFileName), @@(@$t2->OwnerProcess->UniqueProcessId) .printf "%10ma (%0.4x)

", @@(@$t2->CommunicationInfo->ConnectionPort->OwnerProcess->ImageFileName), @@(@$t2->CommunicationInfo->ConnectionPort->OwnerProcess->UniqueProcessId) .break } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 r ? @ $t6 = ( nt ! _LIST_ENTRY * ) @ @ ( nt ! PsActiveProcessHead ) . for ( r ? @ $t7 = @ $t6 -> Flink ; ( @ $t6 != @ $t7 ) ; r ? @ $t7 = @ $t7 -> Flink ) { r ? @ $t8 = #CONTAINING_RECORD(@$t7, nt!_EPROCESS, ActiveProcessLinks) r ? @ $t0 = ( nt ! _LIST_ENTRY * ) @ @ ( nt ! AlpcpPortList ) . for ( r ? @ $t1 = @ $t0 -> Flink ; ( @ $t0 != @ $t1 ) ; r ? @ $t1 = @ $t1 -> Flink ) { r ? @ $t2 = #CONTAINING_RECORD(@$t1, nt!_ALPC_PORT, PortListEntry) . if ( @ @ ( @ $t8 ) == @ @ ( @ $t2 -> OwnerProcess ) ) { . if @ @ ( @ $t2 -> CommunicationInfo -> ConnectionPort ) { . printf / D "<link cmd=\" ! alpc / p @ $t2 \ ">Server Port Info</link> <-> " ; . printf / D "<link cmd=\" ! alpc / p @ @ ( @ $t2 -> CommunicationInfo -> ConnectionPort ) \ ">Connection Port Info</link> | " ; . printf "%10ma (%0.4x) <- " , @ @ ( @ $t2 -> OwnerProcess -> ImageFileName ) , @ @ ( @ $t2 -> OwnerProcess -> UniqueProcessId ) . printf "%10ma (%0.4x)

" , @ @ ( @ $t2 -> CommunicationInfo -> ConnectionPort -> OwnerProcess -> ImageFileName ) , @ @ ( @ $t2 -> CommunicationInfo -> ConnectionPort -> OwnerProcess -> UniqueProcessId ) . break } } } }

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

Server Port Info <-> Connection Port Info | System (0004) <- System (0004) Server Port Info <-> Connection Port Info | smss.exe (0114) <- smss.exe (0114) Server Port Info <-> Connection Port Info | csrss.exe (0170) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | wininit.exe (01b8) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | csrss.exe (01c8) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | services.exe (01fc) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | winlogon.exe (021c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | lsass.exe (0228) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | lsm.exe (0230) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (02bc) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (0308) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | atiesrxx.exe (0338) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (03b4) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (03d8) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (03f4) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (0138) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (03f0) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | atieclxx.exe (048c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | svchost.exe (04e0) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | spoolsv.exe (058c) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (05a8) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | armsvc.exe (0610) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (062c) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | logonsetsvc.ex (0664) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | sqlwriter.exe (06d8) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (06ec) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | ThinkPadKBSvc. (0710) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | WLIDSVC.EXE (0738) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | logonset.exe (04a4) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | WLIDSVCM.EXE (05f4) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (0870) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | taskhost.exe (092c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | dwm.exe (098c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | explorer.exe (099c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | MainCpl.exe (0aa4) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | osd.exe (0aac) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | unsecapp.exe (0b48) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | WmiPrvSE.exe (0bd8) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | wmpnetwk.exe (0bd4) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (0c6c) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | chrome.exe (0ce8) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | Far.exe (0d08) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | conhost.exe (0d10) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | chrome.exe (0d7c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | chrome.exe (0e10) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | HScrollFun.exe (0f98) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | SetSpeed.exe (0fa4) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | netsession_win (0fcc) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | flux.exe (0fd4) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | AdobeARM.exe (083c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | netsession_win (0c5c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | sppsvc.exe (11f8) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | svchost.exe (1290) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | chrome.exe (0a14) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | taskhost.exe (11c4) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | devenv.exe (0494) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | chrome.exe (0134) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | TrustedInstall (0cd0) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | dllhost.exe (0cdc) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | chrome.exe (14e8) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | mscorsvw.exe (1760) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | mscorsvw.exe (17d4) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | notepad.exe (1668) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | Far.exe (11b4) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | conhost.exe (0238) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | SearchIndexer. (16cc) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | windbg.exe (008c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | wuauclt.exe (085c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | notepad.exe (1624) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | audiodg.exe (03c4) <- csrss.exe (0170) Server Port Info <-> Connection Port Info | vmmon64.exe (1434) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | VirtualBox.exe (0b1c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | VBoxSVC.exe (0b60) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | VirtualBox.exe (029c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | windbg.exe (0fc0) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | vcpkgsrv.exe (13e4) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | AcroRd32.exe (0a94) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | AcroRd32.exe (125c) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | chrome.exe (0864) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | chrome.exe (1414) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | chrome.exe (1604) <- csrss.exe (01c8) Server Port Info <-> Connection Port Info | chrome.exe (11a0) <- csrss.exe (01c8) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 Server Port Info < -> Connection Port Info | System ( 0004 ) < - System ( 0004 ) Server Port Info < -> Connection Port Info | smss . exe ( 0114 ) < - smss . exe ( 0114 ) Server Port Info < -> Connection Port Info | csrss . exe ( 0170 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | wininit . exe ( 01b8 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | csrss . exe ( 01c8 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | services . exe ( 01fc ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | winlogon . exe ( 021c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | lsass . exe ( 0228 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | lsm . exe ( 0230 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 02bc ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 0308 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | atiesrxx . exe ( 0338 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 03b4 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 03d8 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 03f4 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 0138 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 03f0 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | atieclxx . exe ( 048c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | svchost . exe ( 04e0 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | spoolsv . exe ( 058c ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 05a8 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | armsvc . exe ( 0610 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 062c ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | logonsetsvc . ex ( 0664 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | sqlwriter . exe ( 06d8 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 06ec ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | ThinkPadKBSvc . ( 0710 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | WLIDSVC . EXE ( 0738 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | logonset . exe ( 04a4 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | WLIDSVCM . EXE ( 05f4 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 0870 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | taskhost . exe ( 092c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | dwm . exe ( 098c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | explorer . exe ( 099c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | MainCpl . exe ( 0aa4 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | osd . exe ( 0aac ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | unsecapp . exe ( 0b48 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | WmiPrvSE . exe ( 0bd8 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | wmpnetwk . exe ( 0bd4 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 0c6c ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | chrome . exe ( 0ce8 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | Far . exe ( 0d08 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | conhost . exe ( 0d10 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | chrome . exe ( 0d7c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | chrome . exe ( 0e10 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | HScrollFun . exe ( 0f98 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | SetSpeed . exe ( 0fa4 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | netsession_win ( 0fcc ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | flux . exe ( 0fd4 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | AdobeARM . exe ( 083c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | netsession_win ( 0c5c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | sppsvc . exe ( 11f8 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | svchost . exe ( 1290 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | chrome . exe ( 0a14 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | taskhost . exe ( 11c4 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | devenv . exe ( 0494 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | chrome . exe ( 0134 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | TrustedInstall ( 0cd0 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | dllhost . exe ( 0cdc ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | chrome . exe ( 14e8 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | mscorsvw . exe ( 1760 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | mscorsvw . exe ( 17d4 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | notepad . exe ( 1668 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | Far . exe ( 11b4 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | conhost . exe ( 0238 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | SearchIndexer . ( 16cc ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | windbg . exe ( 008c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | wuauclt . exe ( 085c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | notepad . exe ( 1624 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | audiodg . exe ( 03c4 ) < - csrss . exe ( 0170 ) Server Port Info < -> Connection Port Info | vmmon64 . exe ( 1434 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | VirtualBox . exe ( 0b1c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | VBoxSVC . exe ( 0b60 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | VirtualBox . exe ( 029c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | windbg . exe ( 0fc0 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | vcpkgsrv . exe ( 13e4 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | AcroRd32 . exe ( 0a94 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | AcroRd32 . exe ( 125c ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | chrome . exe ( 0864 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | chrome . exe ( 1414 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | chrome . exe ( 1604 ) < - csrss . exe ( 01c8 ) Server Port Info < -> Connection Port Info | chrome . exe ( 11a0 ) < - csrss . exe ( 01c8 )

-> 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

lkd> dt nt!_OBJECT_TYPE poi(nt!AlpcPortObjectType) +0x000 TypeList : _LIST_ENTRY [ 0xffffe001`170b9e00 - 0xffffe001`170b9e00 ] +0x010 Name : _UNICODE_STRING "ALPC Port" +0x020 DefaultObject : 0x00000000`000000e1 Void +0x028 Index : 0x26 '&' +0x02c TotalNumberOfObjects : 0x3bc +0x030 TotalNumberOfHandles : 0x3ae +0x034 HighWaterNumberOfObjects : 0x4d1 +0x038 HighWaterNumberOfHandles : 0x4c0 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0b8 TypeLock : _EX_PUSH_LOCK +0x0c0 Key : 0x43504c41 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffffe001`170b9ec8 - 0xffffe001`170b9ec8 ] 1 2 3 4 5 6 7 8 9 10 11 12 13 lkd > dt nt ! _OBJECT_TYPE poi ( nt ! AlpcPortObjectType ) + 0x000 TypeList : _LIST _ ENTRY [ 0xffffe001 ` 170b9e00 - 0xffffe001 ` 170b9e00 ] + 0x010 Name : _UNICODE _ STRING "ALPC Port" + 0x020 DefaultObject : 0x00000000 ` 000000e1 Void + 0x028 Index : 0x26 '&' + 0x02c TotalNumberOfObjects : 0x3bc + 0x030 TotalNumberOfHandles : 0x3ae + 0x034 HighWaterNumberOfObjects : 0x4d1 + 0x038 HighWaterNumberOfHandles : 0x4c0 + 0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER + 0x0b8 TypeLock : _EX_PUSH_LOCK + 0x0c0 Key : 0x43504c41 + 0x0c8 CallbackList : _LIST _ ENTRY [ 0xffffe001 ` 170b9ec8 - 0xffffe001 ` 170b9ec8 ]

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!

Operations 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 :

nt!_ALPC_PORT +0x030 CompletionPacketLookaside : +0x038 Entry : [1] +0x000 ListEntry : _SINGLE_LIST_ENTRY +0x008 Packet : 0xffffe001`18a85150 _IO_MINI_COMPLETION_PACKET_USER +0x010 Lookaside : 0xffffe001`18ca16c0 _ALPC_COMPLETION_PACKET_LOOKASIDE lkd> dt 0xffffe001`18a85150 _IO_MINI_COMPLETION_PACKET_USER ntdll!_IO_MINI_COMPLETION_PACKET_USER +0x000 ListEntry : _LIST_ENTRY [ 0x00000000`00000000 - 0xffffe001`182c0658 ] +0x010 PacketType : 0x5c0004 +0x018 KeyContext : 0x000000f8`3daa8b20 Void +0x020 ApcContext : (null) +0x028 IoStatus : 0n0 +0x030 IoStatusInformation : 0 +0x038 MiniPacketCallback : 0xfffff801`75c6b61c void nt!AlpcpLookasidePacketCallbackRoutine+0 +0x040 Context : 0xffffe001`18ca16f8 Void +0x048 Allocated : 0x1 '' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 nt ! _ALPC_PORT + 0x030 CompletionPacketLookaside : + 0x038 Entry : [ 1 ] + 0x000 ListEntry : _SINGLE_LIST_ENTRY + 0x008 Packet : 0xffffe001 ` 18a85150 _IO_MINI_COMPLETION_PACKET_USER + 0x010 Lookaside : 0xffffe001 ` 18ca16c0 _ALPC_COMPLETION_PACKET_LOOKASIDE lkd > dt 0xffffe001 ` 18a85150 _IO_MINI_COMPLETION_PACKET_USER ntdll ! _IO_MINI_COMPLETION_PACKET_USER + 0x000 ListEntry : _LIST _ ENTRY [ 0x00000000 ` 00000000 - 0xffffe001 ` 182c0658 ] + 0x010 PacketType : 0x5c0004 + 0x018 KeyContext : 0x000000f8 ` 3daa8b20 Void + 0x020 ApcContext : ( null ) + 0x028 IoStatus : 0n0 + 0x030 IoStatusInformation : 0 + 0x038 MiniPacketCallback : 0xfffff801 ` 75c6b61c void nt ! AlpcpLookasidePacketCallbackRoutine + 0 + 0x040 Context : 0xffffe001 ` 18ca16f8 Void + 0x048 Allocated : 0x1 ''

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

lkd> x nt!nt*alpc*port fffff801`760b1e34 nt!NtAlpcCreatePort (<no parameter info>) fffff801`76059204 nt!NtAlpcAcceptConnectPort (<no parameter info>) fffff801`76055ab4 nt!NtAlpcDisconnectPort (<no parameter info>) fffff801`7602e3c0 nt!NtAlpcSendWaitReceivePort (<no parameter info>) fffff801`76074de8 nt!NtAlpcConnectPort (<no parameter info>) fffff801`75fe9030 nt!NtAlpcImpersonateClientOfPort (<no parameter info>) lkd> x nt!alpc*port fffff801`76056330 nt!AlpcpClosePort (<no parameter info>) fffff801`76093dc8 nt!AlpcpDispatchReplyToPort (<no parameter info>) fffff801`75feacd0 nt!AlpcpReferenceConnectedPort (<no parameter info>) fffff801`7605672c nt!AlpcpFlushMessagesPort (<no parameter info>) fffff801`75cebf3c nt!AlpcpQueueIoCompletionPort (<no parameter info>) fffff801`7605a140 nt!AlpcpInitializePort (<no parameter info>) fffff801`760592c8 nt!AlpcpAcceptConnectPort (<no parameter info>) fffff801`75f98d7c nt!AlpcpReferenceMessageByWaitingThreadPort (<no parameter info>) fffff801`760565c4 nt!AlpcpFlushResourcesPort (<no parameter info>) fffff801`76057f0c nt!AlpcpEnumerateResourcesPort (<no parameter info>) fffff801`7605a2f4 nt!AlpcpCreateClientPort (<no parameter info>) fffff801`760b1e98 nt!AlpcpCreateConnectionPort (<no parameter info>) fffff801`760a83f4 nt!AlpcpOpenPort (<no parameter info>) fffff801`76056bc4 nt!AlpcpDisconnectPort (<no parameter info>) fffff801`7605a888 nt!AlpcpSetOwnerProcessPort (<no parameter info>) fffff801`76055fe8 nt!AlpcpDestroyPort (<no parameter info>) fffff801`760756d8 nt!AlpcpConnectPort (<no parameter info>) fffff801`7606d144 nt!AlpcpAssociateIoCompletionPort (<no parameter info>) fffff801`76209900 nt!AlpcpLogClosePort (<no parameter info>) fffff801`76055d58 nt!AlpcpDeletePort (<no parameter info>) fffff801`7602c8e0 nt!AlpcpReceiveMessagePort (<no parameter info>) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 lkd > x nt ! nt* alpc* port fffff801 ` 760b1e34 nt ! NtAlpcCreatePort ( < no parameter info > ) fffff801 ` 76059204 nt ! NtAlpcAcceptConnectPort ( < no parameter info > ) fffff801 ` 76055ab4 nt ! NtAlpcDisconnectPort ( < no parameter info > ) fffff801 ` 7602e3c0 nt ! NtAlpcSendWaitReceivePort ( < no parameter info > ) fffff801 ` 76074de8 nt ! NtAlpcConnectPort ( < no parameter info > ) fffff801 ` 75fe9030 nt ! NtAlpcImpersonateClientOfPort ( < no parameter info > ) lkd > x nt ! alpc* port fffff801 ` 76056330 nt ! AlpcpClosePort ( < no parameter info > ) fffff801 ` 76093dc8 nt ! AlpcpDispatchReplyToPort ( < no parameter info > ) fffff801 ` 75feacd0 nt ! AlpcpReferenceConnectedPort ( < no parameter info > ) fffff801 ` 7605672c nt ! AlpcpFlushMessagesPort ( < no parameter info > ) fffff801 ` 75cebf3c nt ! AlpcpQueueIoCompletionPort ( < no parameter info > ) fffff801 ` 7605a140 nt ! AlpcpInitializePort ( < no parameter info > ) fffff801 ` 760592c8 nt ! AlpcpAcceptConnectPort ( < no parameter info > ) fffff801 ` 75f98d7c nt ! AlpcpReferenceMessageByWaitingThreadPort ( < no parameter info > ) fffff801 ` 760565c4 nt ! AlpcpFlushResourcesPort ( < no parameter info > ) fffff801 ` 76057f0c nt ! AlpcpEnumerateResourcesPort ( < no parameter info > ) fffff801 ` 7605a2f4 nt ! AlpcpCreateClientPort ( < no parameter info > ) fffff801 ` 760b1e98 nt ! AlpcpCreateConnectionPort ( < no parameter info > ) fffff801 ` 760a83f4 nt ! AlpcpOpenPort ( < no parameter info > ) fffff801 ` 76056bc4 nt ! AlpcpDisconnectPort ( < no parameter info > ) fffff801 ` 7605a888 nt ! AlpcpSetOwnerProcessPort ( < no parameter info > ) fffff801 ` 76055fe8 nt ! AlpcpDestroyPort ( < no parameter info > ) fffff801 ` 760756d8 nt ! AlpcpConnectPort ( < no parameter info > ) fffff801 ` 7606d144 nt ! AlpcpAssociateIoCompletionPort ( < no parameter info > ) fffff801 ` 76209900 nt ! AlpcpLogClosePort ( < no parameter info > ) fffff801 ` 76055d58 nt ! AlpcpDeletePort ( < no parameter info > ) fffff801 ` 7602c8e0 nt ! AlpcpReceiveMessagePort ( < no parameter info > )

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

EXTERN_C NTKERNELAPI void NTAPI IoSetIoCompletionEx( __inout void* completitionPort, __in const void* keyContext, __in const void* apcContext, __in ULONG_PTR ioStatus, __in ULONG_PTR ioStatusInformation, __in bool allocPacketInfo, __in const void* ioMiniCoompletitionPacketUser ); 1 2 3 4 5 6 7 8 9 10 11 12 EXTERN_C NTKERNELAPI void NTAPI IoSetIoCompletionEx ( __inout void * completitionPort , __in const void * keyContext , __in const void * apcContext , __in ULONG_PTR ioStatus , __in ULONG_PTR ioStatusInformation , __in bool allocPacketInfo , __in const void * ioMiniCoompletitionPacketUser ) ;

and now how to setup own Callback packet :

std::unique_ptr<void, decltype(&IoFreeMiniCompletionPacket)> m_pPacket( IoAllocateMiniCompletionPacket(MiniPacketCallbackInterceptor, this), IoFreeMiniCompletionPacket); ... bool StartIntercepting( __in _ALPC_PORT* alpcPort, __in void* keyContext ) { ... IoSetIoCompletionEx( alpcPort->CompletionPort, keyContext, nullptr, NULL, NULL, FALSE, m_pPacket); ... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 std :: unique_ptr < void , decltype ( &IoFreeMiniCompletionPacket ) > m_pPacket ( IoAllocateMiniCompletionPacket ( MiniPacketCallbackInterceptor , this ) , IoFreeMiniCompletionPacket ) ; . . . bool StartIntercepting ( __in _ALPC_PORT * alpcPort , __in void * keyContext ) { . . . IoSetIoCompletionEx ( alpcPort -> CompletionPort , keyContext , nullptr , NULL , NULL , FALSE , m_pPacket ) ; . . .

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

!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 : auto obj_dir = RTL_CONSTANT_STRING(L"\\ObjectTypes"); OBJECT_ATTRIBUTES objAttributes; InitializeObjectAttributes( &objAttributes, &obj_dir, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, nullptr); HANDLE h_dir; NTSTATUS status = ZwOpenDirectoryObject(&h_dir, DIRECTORY_QUERY, &objAttributes); if (!NT_SUCCESS(status)) return nullptr; OBJECT_DIRECTORY* object_dir; NTSTATUS status = ObReferenceObjectByHandle(h_dir, 0, 0, KernelMode, &object_dir, nullptr); if (!NT_SUCCESS(status)) return nullptr; for (size_t i = 0; i < _countof(object_dir->HashBuckets); i++) { for (OBJECT_DIRECTORY_ENTRY* dir_entry = object_dir->HashBuckets[i]; dir_entry; dir_entry = dir_entry->ChainLink) { DbgPrint("

Object : %ws", dir_entry->Object->Name.Buffer); if (!RtlCompareUnicodeString(&dir_entry->Object->Name, &objectName, TRUE)) return &dir_entry->Object; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 auto obj_dir = RTL_CONSTANT_STRING ( L "\\ObjectTypes" ) ; OBJECT_ATTRIBUTES objAttributes ; InitializeObjectAttributes ( &objAttributes , &obj_dir , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE , NULL , nullptr ) ; HANDLE h_dir ; NTSTATUS status = ZwOpenDirectoryObject ( &h_dir , DIRECTORY_QUERY , &objAttributes ) ; if ( ! NT_SUCCESS ( status ) ) return nullptr ; OBJECT_DIRECTORY * object_dir ; NTSTATUS status = ObReferenceObjectByHandle ( h_dir , 0 , 0 , KernelMode , &object_dir , nullptr ) ; if ( ! NT_SUCCESS ( status ) ) return nullptr ; for ( size _ t i = 0 ; i < _countof ( object_dir -> HashBuckets ) ; i ++ ) { for ( OBJECT_DIRECTORY_ENTRY * dir_entry = object_dir -> HashBuckets [ i ] ; dir_entry ; dir_entry = dir_entry -> ChainLink ) { DbgPrint ( "

Object : %ws" , dir_entry -> Object -> Name . Buffer ) ; if ( ! RtlCompareUnicodeString ( &dir_entry -> Object -> Name , &objectName , TRUE ) ) return &dir_entry -> Object ; } } 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 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 Object : TmTm Object : Desktop Object : Process Object : DebugObject Object : TpWorkerFactory Object : Adapter Object : Token Object : EventPair Object : PcwObject Object : WmiGuid Object : EtwRegistration Object : Session Object : Timer Object : Mutant Object : IoCompletion Object : WindowStation Object : Profile Object : File Object : Semaphore Object : EtwConsumer Object : TmTx???A~?? Object : SymbolicLink Object : FilterConnectionPort Object : Key Object : KeyedEvent Object : Callback Object : UserApcReserve Object : Job Object : Controller Object : IoCompletionReserve Object : Device Object : Directory Object : Section Object : TmEn Object : Thread Object : Type Object : FilterCommunicationPort Object : PowerRequest Object : TmRm Object : Event Object : ALPC Port Object : TmTm Object : Desktop Object : Process Object : DebugObject Object : TpWorkerFactory Object : Adapter Object : Token Object : EventPair Object : PcwObject Object : WmiGuid Object : EtwRegistration Object : Session Object : Timer Object : Mutant Object : IoCompletion Object : WindowStation Object : Profile Object : File Object : Semaphore Object : EtwConsumer Object : TmTx???A~?? Object : SymbolicLink Object : FilterConnectionPort Object : Key Object : KeyedEvent Object : Callback Object : UserApcReserve Object : Job Object : Controller Object : IoCompletionReserve Object : Device Object : Directory Object : Section Object : TmEn Object : Thread Object : Type Object : FilterCommunicationPort Object : PowerRequest Object : TmRm Object : Event Object : ALPC Port Object : Driver 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 Object : TmTm Object : Desktop Object : Process Object : DebugObject Object : TpWorkerFactory Object : Adapter Object : Token Object : EventPair Object : PcwObject Object : WmiGuid Object : EtwRegistration Object : Session Object : Timer Object : Mutant Object : IoCompletion Object : WindowStation Object : Profile Object : File Object : Semaphore Object : EtwConsumer Object : TmTx ? ? ? A ~ ? ? Object : SymbolicLink Object : FilterConnectionPort Object : Key Object : KeyedEvent Object : Callback Object : UserApcReserve Object : Job Object : Controller Object : IoCompletionReserve Object : Device Object : Directory Object : Section Object : TmEn Object : Thread Object : Type Object : FilterCommunicationPort Object : PowerRequest Object : TmRm Object : Event Object : ALPC Port Object : TmTm Object : Desktop Object : Process Object : DebugObject Object : TpWorkerFactory Object : Adapter Object : Token Object : EventPair Object : PcwObject Object : WmiGuid Object : EtwRegistration Object : Session Object : Timer Object : Mutant Object : IoCompletion Object : WindowStation Object : Profile Object : File Object : Semaphore Object : EtwConsumer Object : TmTx ? ? ? A ~ ? ? Object : SymbolicLink Object : FilterConnectionPort Object : Key Object : KeyedEvent Object : Callback Object : UserApcReserve Object : Job Object : Controller Object : IoCompletionReserve Object : Device Object : Directory Object : Section Object : TmEn Object : Thread Object : Type Object : FilterCommunicationPort Object : PowerRequest Object : TmRm Object : Event Object : ALPC Port Object : Driver a lot of object to query for, what are the object types of theirs ? kd> x nt!*objecttype fffff800`02871780 nt!TmResourceManagerObjectType = <no type information> fffff800`028fd5e0 nt!IoDeviceHandlerObjectType = <no type information> fffff800`028fc3a0 nt!ExMutantObjectType = <no type information> fffff800`028fc3a8 nt!ExTimerObjectType = <no type information> fffff800`028737e8 nt!ObpTypeObjectType = <no type information> fffff800`028737e0 nt!ObpDirectoryObjectType = <no type information> fffff800`028fc180 nt!IoDriverObjectType = <no type information> fffff800`028683e8 nt!ExpWorkerFactoryObjectType = <no type information> fffff800`028fc1d8 nt!IoCompletionObjectType = <no type information> fffff800`02867430 nt!EtwpRegistrationObjectType = <no type information> fffff800`028795f0 nt!MmSessionObjectType = <no type information> fffff800`028bd8a0 nt!LpcWaitablePortObjectType = <no type information> fffff800`02870450 nt!WmipGuidObjectType = <no type information> fffff800`028fc110 nt!MmSectionObjectType = <no type information> fffff800`028fc298 nt!ExEventPairObjectType = <no type information> fffff800`02a40ba0 nt!SepSetAuditInfoForObjectType (<no parameter info>) fffff800`028bd8a8 nt!LpcPortObjectType = <no type information> fffff800`02b91050 nt!CmKeyObjectType = <no type information> fffff800`028717a0 nt!TmTransactionObjectType = <no type information> fffff800`028fc6c8 nt!IoControllerObjectType = <no type information> fffff800`028682f8 nt!ExProfileObjectType = <no type information> fffff800`028fc0a0 nt!ExEventObjectType = <no type information> fffff800`028fc838 nt!IoAdapterObjectType = <no type information> fffff800`02868258 nt!ExpKeyedEventObjectType = <no type information> fffff800`02b91070 nt!SeTokenObjectType = <no type information> fffff800`02868760 nt!ExWindowStationObjectType = <no type information> fffff800`028fc398 nt!ExSemaphoreObjectType = <no type information> fffff800`0297bb54 nt!ObGetObjectType (<no parameter info>) fffff800`028fc048 nt!IoFileObjectType = <no type information> fffff800`028717a8 nt!TmEnlistmentObjectType = <no type information> fffff800`02867568 nt!EtwpRealTimeConnectionObjectType = <no type information> fffff800`028b9858 nt!AlpcPortObjectType = <no type information> fffff800`02871778 nt!TmTransactionManagerObjectType = <no type information> fffff800`026edb30 nt!SeComputeAutoInheritByObjectType (<no parameter info>) fffff800`02853f40 nt!DbgkDebugObjectType = <no type information> fffff800`028fc540 nt!IoDeviceObjectType = <no type information> fffff800`02ad55d0 nt!ObCreateObjectType (<no parameter info>) fffff800`028737d8 nt!ObpSymbolicLinkObjectType = <no type information> fffff800`02864e10 nt!PopPowerRequestObjectType = <no type information> fffff800`02868910 nt!ExCallbackObjectType = <no type information> fffff800`02868758 nt!ExDesktopObjectType = <no type information> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 kd > x nt ! * objecttype fffff800 ` 02871780 nt ! TmResourceManagerObjectType = < no type information > fffff800 ` 028fd5e0 nt ! IoDeviceHandlerObjectType = < no type information > fffff800 ` 028fc3a0 nt ! ExMutantObjectType = < no type information > fffff800 ` 028fc3a8 nt ! ExTimerObjectType = < no type information > fffff800 ` 028737e8 nt ! ObpTypeObjectType = < no type information > fffff800 ` 028737e0 nt ! ObpDirectoryObjectType = < no type information > fffff800 ` 028fc180 nt ! IoDriverObjectType = < no type information > fffff800 ` 028683e8 nt ! ExpWorkerFactoryObjectType = < no type information > fffff800 ` 028fc1d8 nt ! IoCompletionObjectType = < no type information > fffff800 ` 02867430 nt ! EtwpRegistrationObjectType = < no type information > fffff800 ` 028795f0 nt ! MmSessionObjectType = < no type information > fffff800 ` 028bd8a0 nt ! LpcWaitablePortObjectType = < no type information > fffff800 ` 02870450 nt ! WmipGuidObjectType = < no type information > fffff800 ` 028fc110 nt ! MmSectionObjectType = < no type information > fffff800 ` 028fc298 nt ! ExEventPairObjectType = < no type information > fffff800 ` 02a40ba0 nt ! SepSetAuditInfoForObjectType ( < no parameter info > ) fffff800 ` 028bd8a8 nt ! LpcPortObjectType = < no type information > fffff800 ` 02b91050 nt ! CmKeyObjectType = < no type information > fffff800 ` 028717a0 nt ! TmTransactionObjectType = < no type information > fffff800 ` 028fc6c8 nt ! IoControllerObjectType = < no type information > fffff800 ` 028682f8 nt ! ExProfileObjectType = < no type information > fffff800 ` 028fc0a0 nt ! ExEventObjectType = < no type information > fffff800 ` 028fc838 nt ! IoAdapterObjectType = < no type information > fffff800 ` 02868258 nt ! ExpKeyedEventObjectType = < no type information > fffff800 ` 02b91070 nt ! SeTokenObjectType = < no type information > fffff800 ` 02868760 nt ! ExWindowStationObjectType = < no type information > fffff800 ` 028fc398 nt ! ExSemaphoreObjectType = < no type information > fffff800 ` 0297bb54 nt ! ObGetObjectType ( < no parameter info > ) fffff800 ` 028fc048 nt ! IoFileObjectType = < no type information > fffff800 ` 028717a8 nt ! TmEnlistmentObjectType = < no type information > fffff800 ` 02867568 nt ! EtwpRealTimeConnectionObjectType = < no type information > fffff800 ` 028b9858 nt ! AlpcPortObjectType = < no type information > fffff800 ` 02871778 nt ! TmTransactionManagerObjectType = < no type information > fffff800 ` 026edb30 nt ! SeComputeAutoInheritByObjectType ( < no parameter info > ) fffff800 ` 02853f40 nt ! DbgkDebugObjectType = < no type information > fffff800 ` 028fc540 nt ! IoDeviceObjectType = < no type information > fffff800 ` 02ad55d0 nt ! ObCreateObjectType ( < no parameter info > ) fffff800 ` 028737d8 nt ! ObpSymbolicLinkObjectType = < no type information > fffff800 ` 02864e10 nt ! PopPowerRequestObjectType = < no type information > fffff800 ` 02868910 nt ! ExCallbackObjectType = < no type information > fffff800 ` 02868758 nt ! ExDesktopObjectType = < no type information > and how many are officialy supported and exported for kernel dev ? extern POBJECT_TYPE *CmKeyObjectType; extern POBJECT_TYPE *IoFileObjectType; extern POBJECT_TYPE *ExEventObjectType; extern POBJECT_TYPE *ExSemaphoreObjectType; extern POBJECT_TYPE *TmTransactionManagerObjectType; extern POBJECT_TYPE *TmResourceManagerObjectType; extern POBJECT_TYPE *TmEnlistmentObjectType; extern POBJECT_TYPE *TmTransactionObjectType; extern POBJECT_TYPE *PsProcessType; extern POBJECT_TYPE *PsThreadType; extern POBJECT_TYPE *SeTokenObjectType; 1 2 3 4 5 6 7 8 9 10 11 extern POBJECT_TYPE * CmKeyObjectType ; extern POBJECT_TYPE * IoFileObjectType ; extern POBJECT_TYPE * ExEventObjectType ; extern POBJECT_TYPE * ExSemaphoreObjectType ; extern POBJECT_TYPE * TmTransactionManagerObjectType ; extern POBJECT_TYPE * TmResourceManagerObjectType ; extern POBJECT_TYPE * TmEnlistmentObjectType ; extern POBJECT_TYPE * TmTransactionObjectType ; extern POBJECT_TYPE * PsProcessType ; extern POBJECT_TYPE * PsThreadType ; extern POBJECT_TYPE * SeTokenObjectType ; 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” lkd> dt nt!_OBJECT_TYPE poi(nt!AlpcPortObjectType) -b +0x000 TypeList : _LIST_ENTRY [ 0xffffe001`170b9e00 - 0xffffe001`170b9e00 ] +0x000 Flink : 0xffffe001`170b9e00 +0x008 Blink : 0xffffe001`170b9e00 +0x010 Name : _UNICODE_STRING "ALPC Port" +0x000 Length : 0x12 +0x002 MaximumLength : 0x14 +0x008 Buffer : 0xffffc000`2c287190 "ALPC Port" +0x020 DefaultObject : 0x00000000`000000e1 +0x028 Index : 0x26 '&' +0x02c TotalNumberOfObjects : 0x3c4 +0x030 TotalNumberOfHandles : 0x3b7 +0x034 HighWaterNumberOfObjects : 0x4d1 +0x038 HighWaterNumberOfHandles : 0x4c0 +0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x000 Length : 0x78 +0x002 ObjectTypeFlags : 0x10 '' +0x002 CaseInsensitive : 0y0 +0x002 UnnamedObjectsOnly : 0y0 +0x002 UseDefaultObject : 0y0 +0x002 SecurityRequired : 0y0 +0x002 MaintainHandleCount : 0y1 +0x002 MaintainTypeList : 0y0 +0x002 SupportsObjectCallbacks : 0y0 +0x002 CacheAligned : 0y0 +0x004 ObjectTypeCode : 0 +0x008 InvalidAttributes : 0x80 +0x00c GenericMapping : _GENERIC_MAPPING +0x000 GenericRead : 0x20001 +0x004 GenericWrite : 0x10001 +0x008 GenericExecute : 0 +0x00c GenericAll : 0x1f0001 +0x01c ValidAccessMask : 0x1f0001 +0x020 RetainAccess : 0 +0x024 PoolType : 200 ( NonPagedPoolNx ) +0x028 DefaultPagedPoolCharge : 0 +0x02c DefaultNonPagedPoolCharge : 0x248 +0x030 DumpProcedure : (null) +0x038 OpenProcedure : 0xfffff801`760a83f4 +0x040 CloseProcedure : 0xfffff801`76056330 +0x048 DeleteProcedure : 0xfffff801`76055d58 +0x050 ParseProcedure : (null) +0x058 SecurityProcedure : 0xfffff801`75fe0e44 +0x060 QueryNameProcedure : (null) +0x068 OkayToCloseProcedure : (null) +0x070 WaitObjectFlagMask : 0 +0x074 WaitObjectFlagOffset : 0 +0x076 WaitObjectPointerOffset : 0 +0x0b8 TypeLock : _EX_PUSH_LOCK +0x000 Locked : 0y0 +0x000 Waiting : 0y0 +0x000 Waking : 0y0 +0x000 MultipleShared : 0y0 +0x000 Shared : 0y000000000000000000000000000000000000000000000000000000000000 (0) +0x000 Value : 0 +0x000 Ptr : (null) +0x0c0 Key : 0x43504c41 +0x0c8 CallbackList : _LIST_ENTRY [ 0xffffe001`170b9ec8 - 0xffffe001`170b9ec8 ] +0x000 Flink : 0xffffe001`170b9ec8 +0x008 Blink : 0xffffe001`170b9ec8 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 lkd > dt nt ! _OBJECT_TYPE poi ( nt ! AlpcPortObjectType ) - b + 0x000 TypeList : _LIST _ ENTRY [ 0xffffe001 ` 170b9e00 - 0xffffe001 ` 170b9e00 ] + 0x000 Flink : 0xffffe001 ` 170b9e00 + 0x008 Blink : 0xffffe001 ` 170b9e00 + 0x010 Name : _UNICODE _ STRING "ALPC Port" + 0x000 Length : 0x12 + 0x002 MaximumLength : 0x14 + 0x008 Buffer : 0xffffc000 ` 2c287190 "ALPC Port" + 0x020 DefaultObject : 0x00000000 ` 000000e1 + 0x028 Index : 0x26 '&' + 0x02c TotalNumberOfObjects : 0x3c4 + 0x030 TotalNumberOfHandles : 0x3b7 + 0x034 HighWaterNumberOfObjects : 0x4d1 + 0x038 HighWaterNumberOfHandles : 0x4c0 + 0x040 TypeInfo : _OBJECT_TYPE_INITIALIZER + 0x000 Length : 0x78 + 0x002 ObjectTypeFlags : 0x10 '' + 0x002 CaseInsensitive : 0y0 + 0x002 UnnamedObjectsOnly : 0y0 + 0x002 UseDefaultObject : 0y0 + 0x002 SecurityRequired : 0y0 + 0x002 MaintainHandleCount : 0y1 + 0x002 MaintainTypeList : 0y0 + 0x002 SupportsObjectCallbacks : 0y0 + 0x002 CacheAligned : 0y0 + 0x004 ObjectTypeCode : 0 + 0x008 InvalidAttributes : 0x80 + 0x00c GenericMapping : _GENERIC_MAPPING + 0x000 GenericRead : 0x20001 + 0x004 GenericWrite : 0x10001 + 0x008 GenericExecute : 0 + 0x00c GenericAll : 0x1f0001 + 0x01c ValidAccessMask : 0x1f0001 + 0x020 RetainAccess : 0 + 0x024 PoolType : 200 ( NonPagedPoolNx ) + 0x028 DefaultPagedPoolCharge : 0 + 0x02c DefaultNonPagedPoolCharge : 0x248 + 0x030 DumpProcedure : ( null ) + 0x038 OpenProcedure : 0xfffff801 ` 760a83f4 + 0x040 CloseProcedure : 0xfffff801 ` 76056330 + 0x048 DeleteProcedure : 0xfffff801 ` 76055d58 + 0x050 ParseProcedure : ( null ) + 0x058 SecurityProcedure : 0xfffff801 ` 75fe0e44 + 0x060 QueryNameProcedure : ( null ) + 0x068 OkayToCloseProcedure : ( null ) + 0x070 WaitObjectFlagMask : 0 + 0x074 WaitObjectFlagOffset : 0 + 0x076 WaitObjectPointerOffset : 0 + 0x0b8 TypeLock : _EX_PUSH_LOCK + 0x000 Locked : 0y0 + 0x000 Waiting : 0y0 + 0x000 Waking : 0y0 + 0x000 MultipleShared : 0y0 + 0x000 Shared : 0y000000000000000000000000000000000000000000000000000000000000 ( 0 ) + 0x000 Value : 0 + 0x000 Ptr : ( null ) + 0x0c0 Key : 0x43504c41 + 0x0c8 CallbackList : _LIST _ ENTRY [ 0xffffe001 ` 170b9ec8 - 0xffffe001 ` 170b9ec8 ] + 0x000 Flink : 0xffffe001 ` 170b9ec8 + 0x008 Blink : 0xffffe001 ` 170b9ec8 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

void CAlpcMonitor::CreateImageNotify( __in_opt UNICODE_STRING* fullImageName, __in HANDLE processId, __in IMAGE_INFO* imageInfo ) { if (!imageInfo) return; auto proc = CProcessMonitor::GetInstance().ProcContainer().ObtainRef(processId); if (!proc.get()) return; if (!proc->IsNetworkProcess) return; CAutoLock<EX_PUSH_LOCK, CSharedLockWorker> lock(&CNt::GetInstance().AlpcInfo()->AlpcpPortListLock); for (auto port = CNt::GetInstance().AlpcInfo()->AlpcpPortList; port != CNt::GetInstance().AlpcInfo()->AlpcpPortListTail; port = CONTAINING_RECORD(port->PortListEntry.Flink, _ALPC_PORT, PortListEntry)) { if (!port->OwnerProcess) continue; if (processId != PsGetProcessId(port->OwnerProcess)) continue; InstallHook(port); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 void CAlpcMonitor :: CreateImageNotify ( __in_opt UNICODE_STRING * fullImageName , __in HANDLE processId , __in IMAGE_INFO * imageInfo ) { if ( ! imageInfo ) return ; auto proc = CProcessMonitor :: GetInstance ( ) . ProcContainer ( ) . ObtainRef ( processId ) ; if ( ! proc . get ( ) ) return ; if ( ! proc -> IsNetworkProcess ) return ; CAutoLock < EX_PUSH_LOCK , CSharedLockWorker > lock ( &CNt :: GetInstance ( ) . AlpcInfo ( ) -> AlpcpPortListLock ) ; for ( auto port = CNt :: GetInstance ( ) . AlpcInfo ( ) -> AlpcpPortList ; port != CNt :: GetInstance ( ) . AlpcInfo ( ) -> AlpcpPortListTail ; port = CONTAINING_RECORD ( port -> PortListEntry . Flink , _ALPC_PORT , PortListEntry ) ) { if ( ! port -> OwnerProcess ) continue ; if ( processId != PsGetProcessId ( port -> OwnerProcess ) ) continue ; InstallHook ( port ) ; } }

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!

service : PlugPlay service : Power service : DcomLaunch service : RpcEptMapper service : RpcSs service : eventlog service : AudioEndpointBuilder service : MMCSS service : AudioSrv service : CscService service : gpsvc service : ProfSvc service : Themes service : EventSystem service : SENS service : UxSms service : SamSs service : lmhosts service : nsi service : Dhcp service : Dnscache service : ShellHWDetection service : Schedule service : Spooler service : BFE service : MpsSvc service : LanmanWorkstation service : CryptSvc service : DPS service : FDResPub service : NlaSvc service : PcaSvc service : SysMain service : TrkWks service : Winmgmt service : iphlpsvc service : LanmanServer service : netprofm service : WdiServiceHost service : WPDBusEnum service : WdiSystemHost service : WinHttpAutoProxySvc service : Browser service : WSearch service : Netman service : WMPNetworkSvc service : fdPHost service : HomeGroupProvider service : SSDPSRV service : BITS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 service : PlugPlay service : Power service : DcomLaunch service : RpcEptMapper service : RpcSs service : eventlog service : AudioEndpointBuilder service : MMCSS service : AudioSrv service : CscService service : gpsvc service : ProfSvc service : Themes service : EventSystem service : SENS service : UxSms service : SamSs service : lmhosts service : nsi service : Dhcp service : Dnscache service : ShellHWDetection service : Schedule service : Spooler service : BFE service : MpsSvc service : LanmanWorkstation service : CryptSvc service : DPS service : FDResPub service : NlaSvc service : PcaSvc service : SysMain service : TrkWks service : Winmgmt service : iphlpsvc service : LanmanServer service : netprofm service : WdiServiceHost service : WPDBusEnum service : WdiSystemHost service : WinHttpAutoProxySvc service : Browser service : WSearch service : Netman service : WMPNetworkSvc service : fdPHost service : HomeGroupProvider service : SSDPSRV service : BITS

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 :

//ULONG_PTR KeyContext[]; enum KeyContextMembers { TppAlpcpExecuteCallback = 0, //ntdll AlpcPortType = 2, TppAlpcpCleanupGroupMemberVFuncs = 3, //ntdll LrpcIoComplete = 12, //rpcrt4 LrpcServerIoHandlerPtr = 13, //rpcrt4 SubProcessTag = 15, //TEB }; 1 2 3 4 5 6 7 8 9 10 //ULONG_PTR KeyContext[]; enum KeyContextMembers { TppAlpcpExecuteCallback = 0 , //ntdll AlpcPortType = 2 , TppAlpcpCleanupGroupMemberVFuncs = 3 , //ntdll LrpcIoComplete = 12 , //rpcrt4 LrpcServerIoHandlerPtr = 13 , //rpcrt4 SubProcessTag = 15 , //TEB } ;

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!