Looking at a callstack that is making a COM call to another apartment, look for the SendReceive2
stack frame.
0:053> kb # ChildEBP RetAddr Args to Child 00 1532ed98 752e0ca9 00000002 1532ef44 00000001 ntdll!NtWaitForMultipleObjects+0xc 01 1532ef1c 756dc2a0 1532eef4 1532ef44 00000000 KERNELBASE!WaitForMultipleObjectsEx+0xdc 02 1532ef74 75bec1db 00000000 1532efcc 000003e8 user32!MsgWaitForMultipleObjectsEx+0x159 03 1532efac 75beb438 1532efcc 00000001 1532efd0 combase!CCliModalLoop::BlockFn+0x101 04 (Inline) -------- -------- -------- -------- combase!ModalLoop+0x50 05 1532efd4 75cb4e2f ffffffff 00000000 1532f280 combase!ClassicSTAThreadDispatchCrossApartmentCall+0x133 06 (Inline) -------- -------- -------- -------- combase!CRpcChannelBuffer::SwitchAptAndDispatchCall+0x3839 07 1532f124 75bec6ac 12d8c33c 1532f280 1532f268 combase!CRpcChannelBuffer::SendReceive2+0x631 08 (Inline) -------- -------- -------- -------- combase!ClientCallRetryContext::SendReceiveWithRetry+0x1d 09 (Inline) -------- -------- -------- -------- combase!CAptRpcChnl::SendReceiveInRetryContext+0x27 0a 1532f1e4 75bb3b8f 12d8c33c 1532f280 1532f268 combase!ClassicSTAThreadSendReceive+0x209 0b (Inline) -------- -------- -------- -------- combase!CAptRpcChnl::SendReceive+0x8b 0c 1532f244 75cb14a5 12d8c33c 1532f280 1532f268 combase!CCtxComChnl::SendReceive+0xf9 0d 1532f25c 7596470c 134215b4 1532f2ac 759def05 combase!NdrExtpProxySendReceive+0x42 0e 1532f268 759def05 359a4ea5 00000000 1532f6dc rpcrt4!NdrpProxySendReceive+0xe 0f 1532f6a8 75cb1a1e 12ee7418 12ee7568 1532f6dc rpcrt4!NdrClientCall2+0x2d6 10 1532f6c4 75bb3a83 00000008 00000007 1532f74c combase!ObjectStublessClient+0x6b 11 1532f6d4 12859a06 134215b4 7ad8e84f 00000000 combase!ObjectStubless+0xf 12 1532f74c 74f4f2e9 0c1e4e20 34fd899b 00000000 CONTOSO!DoSomething+0x216 13 1532f784 74f4f2cd 00000000 1532f79c 75d0919f msvcr110!_beginthreadex+0xb4
What we need is the first argument to combase!CRpcChannelBuffer::SendReceive2
which, in this case, is: 12d8c33c
.
Here's where things get tricky. Since we don't have the private symbols for that struct, and the !SIEExtsPub.ComCalls
extension command is now defunct and hasn't been updated to the new layout of the struct, we'll have to wing it and figure it out ourselves.
0:053> dc 0x12d8c33c 12d8c33c 75ba5c10 75bc0928 75bb1ab4 adb1682c .\.u(..u...u,h.. 12d8c34c 429b3908 2b59b182 e6a936e1 00000003 .9.B..Y+.6...... 12d8c35c 00000022 04cbbf68 00000000 00f7bf40 "...h.......@...
As I mentioned, the layout of this struct changes. What I've found works best on most versions of Windows is to pick the 4th DWORD
after value 00000003
, which is 00f7bf40
. This does tend to move in various versions of combase.dll
.
It points to another struct containing the target process and thread...
0:053> dc 0x00f7bf40 00f7bf40 00f7c238 0471a7b0 000005a0 00001cb0 8.....q.........
Got it! The target process id is 05a0
and the thread id is 1cb0
.