Tuesday, July 6, 2010

COM: GetToSTA

When a COM call is made to STA (single-threaded apartment) COM, ole32!GetToSTA is called to send the COM call to target STA thread. An example below shows that a thread was created for RPC server call (SCALL) and its call was dispatched to a WMI provider which is a (STA) COM component. Once the COM call is made to STA thread, the thread (tid=4) is waiting for a event which will be set by STA thread when the COM call is finished.
0:004> kL
ChildEBP RetAddr 
00c9e5b0 77175e6c ntdll!KiFastSystemCallRet
00c9e5b4 7532179c ntdll!ZwWaitForSingleObject+0xc
00c9e620 75a0f003 KERNELBASE!WaitForSingleObjectEx+0x98
00c9e638 75a0efb2 kernel32!WaitForSingleObjectExImplementation+0x75
00c9e64c 75ca88df kernel32!WaitForSingleObject+0x12
00c9e670 75dca819 ole32!GetToSTA+0xad
00c9e6a0 75dcc05f ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0x140
00c9e780 75cbd0e5 ole32!CRpcChannelBuffer::SendReceive2+0xef
00c9e7fc 75cbcb09 ole32!CAptRpcChnl::SendReceive+0xaf
00c9e850 75dcbf75 ole32!CCtxComChnl::SendReceive+0x1c5
00c9e86c 76c5178b ole32!NdrExtpProxySendReceive+0x49
00c9e878 76cc5744 RPCRT4!NdrpProxySendReceive+0xe
00c9ec90 75dcba02 RPCRT4!NdrClientCall2+0x1a6
00c9ecb0 75cbc8b5 ole32!ObjectStublessClient+0xa2
00c9ecc0 6b23f6a3 ole32!ObjectStubless+0xf
00c9ecf8 0027d9d9 FastProx!CWbemSvcWrapper::XWbemServices::CreateInstanceEnumAsync+0x6e
00c9ed28 00263778 wmiprvse!CServerObject_StaThread::CreateInstanceEnumAsync+0x92
00c9ed68 002635dc wmiprvse!CInterceptor_IWbemSyncProvider::Helper_CreateInstanceEnumAsync+0x159
00c9edac 76c5fc8f wmiprvse!CInterceptor_IWbemSyncProvider::CreateInstanceEnumAsync+0xf4
00c9edd4 76cc4c53 RPCRT4!Invoke+0x2a
00c9f1dc 75dcd936 RPCRT4!NdrStubCall2+0x2d6
00c9f224 6b234f55 ole32!CStdStubBuffer_Invoke+0xb6
00c9f238 75dcd9c6 FastProx!CBaseStublet::Invoke+0x29
00c9f280 75dcdf1f ole32!SyncStubInvoke+0x3c
00c9f2cc 75ce213c ole32!StubInvoke+0xb9
00c9f3a8 75ce2031 ole32!CCtxComChnl::ContextInvoke+0xfa
00c9f3c4 75dca754 ole32!MTAInvoke+0x1a
00c9f3f4 75dcdcbb ole32!AppInvoke+0xab
00c9f4d4 75dca773 ole32!ComInvokeWithLockAndIPID+0x372
00c9f520 76c5f34a ole32!ThreadInvoke+0x302
00c9f55c 76c5f4da RPCRT4!DispatchToStubInCNoAvrf+0x4a
00c9f5b4 76c5f3c6 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0x16c
00c9f5dc 76c60cef RPCRT4!RPC_INTERFACE::DispatchToStub+0x8b
00c9f614 76c5f882 RPCRT4!RPC_INTERFACE::DispatchToStubWithObject+0xb2
00c9f660 76c5f7a4 RPCRT4!LRPC_SCALL::DispatchRequest+0x23b
00c9f680 76c5f763 RPCRT4!LRPC_SCALL::QueueOrDispatchCall+0xbd
00c9f69c 76c5f5ff RPCRT4!LRPC_SCALL::HandleRequest+0x34f
00c9f6d0 76c5f573 RPCRT4!LRPC_SASSOCIATION::HandleRequest+0x144
00c9f708 76c5ee4f RPCRT4!LRPC_ADDRESS::HandleRequest+0xbd
00c9f780 76c5ece7 RPCRT4!LRPC_ADDRESS::ProcessIO+0x50a
00c9f78c 76c61357 RPCRT4!LrpcServerIoHandler+0x16
00c9f79c 7715d3a3 RPCRT4!LrpcIoComplete+0x16
00c9f7c4 77160748 ntdll!TppAlpcpExecuteCallback+0x1c5
00c9f92c 75a11194 ntdll!TppWorkerThread+0x5a4
00c9f938 7718b3f5 kernel32!BaseThreadInitThunk+0xe
00c9f978 7718b3c8 ntdll!__RtlUserThreadStart+0x70
00c9f990 00000000 ntdll!_RtlUserThreadStart+0x1b
0:004> kpL
ChildEBP RetAddr 
00c9e5b0 77175e6c ntdll!KiFastSystemCallRet(void)
00c9e5b4 7532179c ntdll!ZwWaitForSingleObject(void)+0xc
.......
00c9e670 75dca819 ole32!GetToSTA(class OXIDEntry * pOXIDEntry = 0x00333918, class CMessageCall * pCall = 0x0036af18)+0xad
.......
As you see above, GetToSTA takes 2 parameters. One for OXIDEntry object pointer and the other for CMessageCall object pointer. If we look into the first parameter, it provides some useful information.
0:004> dt OXIDEntry 0x00333918
ole32!OXIDEntry
   +0x000 _pNext           : 0x75dd68f8 OXIDEntry
   +0x004 _pPrev           : 0x00333898 OXIDEntry
   +0x008 _dwPid           : 0x204
   +0x00c _dwTid           : 0x16bc
   +0x010 _moxid           : _GUID {9feeca0e-6667-eb70-3925-cbaa316f4a29}
   +0x020 _mid             : 0x294a6f31`aacb2539
   +0x028 _ipidRundown     : _GUID {0000380d-0204-16bc-3099-d83e8ae297f6}
   +0x038 _dwFlags         : 0x303
   +0x03c _hServerSTA      : 0x0c4400f0 HWND__
   +0x040 _pParentApt      : 0x003498e0 CComApartment
   +0x044 _pRpc            : (null)
   +0x048 _pAuthId         : (null)
   +0x04c _pBinding        : (null)
   +0x050 _dwAuthnHint     : 1
   +0x054 _dwAuthnSvc      : 0xffffffff
   +0x058 _pMIDEntry       : 0x003336f0 MIDEntry
   +0x05c _pRUSTA          : 0x0035255c IRemUnknown
   +0x060 _cRefs           : 0n13
   +0x064 _hComplete       : (null)
   +0x068 _cCalls          : 0n1
   +0x06c _cResolverRef    : 0n0
   +0x070 _dwExpiredTime   : 0
   ......
dwPid and dwTid indicate the process id and thread id to which the COM call is made. In this case thread 4 is making a COM call to thread 7 (PID 0x204, TID 0x16bc) where the STA COM object resides.
0:007> ~
.......

.  7  Id: 204.16bc Suspend: 1 Teb: 7ffd8000 Unfrozen
.......
When a COM call is made, STA thread receives the call, translates it to window message and put it into hidden window message queue. STA thread processes the message from the queue and set event when the COM method is done. This will release Wait function in caller thread (id=4 in above case).

No comments:

Post a Comment