当前位置: 首页 > news >正文

TERMSRV!WinStationLpcThread函数和TERMSRV!WinStationLpcHandleConnectionRequest函数分析

WinStationLpcThread函数和WinStationLpcHandleConnectionRequest函数分析

第一部分:调试记录部分:

04:05:41.953 8981FF7C.E13E5450 TERMSRV: WinStation LPC Service Thread got a message
04:05:41.953 8981FF7C.E13E5450 TERMSRV: WinStation LPC Service Thread got connection message
04:05:41.953 8981FF7C.E13E5450 TERMSRV: WinStationLpcHandleConnectionRequest called
04:05:41.953 8981FF7C.E13E5450 TERMSRV: WSTAPI: Creating View memory
04:05:41.953 8981FF7C.E13E5450 TERMSRV: WSTAPI: Calling AcceptConnectPort, Accept 1
04:05:41.953 8981FF7C.E13E5450 TERMSRV: pContext 000F0670, ConnectionRequest 027FFEAC, info 027FFEC4
04:05:41.953 8981FF7C.E13E5450 TERMSRV: ViewBase 024B0000, ViewSize 0x2000, ViewRemoteBase 00640000
04:05:41.953 8981FF7C.E13E5450 TERMSRV: WSTAPI: Calling CompleteConnect port 00000334
04:05:41.953 8981FF7C.E13E5450 TERMSRV: WinStation LPC Connection Accepted, Logonid 9 pContext 000F0670 Status 0x0
04:05:41.953 8984492C.E12576D8 TERMSRV: WinStation LPC Service Thread got a message
04:05:41.953 8984492C.E12576D8 TERMSRV: WinStation LPC Service Thread got WinStationGetSMCommand message
04:05:41.953 8984492C.E12576D8 TERMSRV: WinStationGetSMCommand, LogonId=9
04:05:41.953 8984492C.E12576D8 TERMSRV: WinStationGetSMCommand queue empty port 00000334

第二部分:

/*****************************************************************************
*
*  WinStationLpcThread
*
*   Main service thread for internal Winstation LPC connections.
*
* ENTRY:
*    ThreadParameter (input)
*      Not used standard NT ThreadCreate() parameter
*
* EXIT:
*   Should never exit
*
****************************************************************************/


NTSTATUS
WinStationLpcThread( IN PVOID ThreadParameter )
{
WINSTATION_APIMSG ApiMsg;
PWINSTATION_APIMSG ReplyMsg;
PLPC_CLIENT_CONTEXT pContext;
NTSTATUS Status;
HANDLE Handle;

    ReplyMsg = NULL;

    /*
* Loop forever processing API requests
*/
for ( ; ; ) {

        /*
* If there are more than the minimum number of API threads active,
* and at least 1 waiting thread, then this thread will terminate.
* But first, any pending reply message must be sent.
*/
RtlEnterCriticalSection( &ApiThreadLock );
#ifdef notdef
if ( NumApiThreads > MinApiThreads && WaitingApiThreads ) {
NumApiThreads--;
RtlLeaveCriticalSection( &ApiThreadLock );
if ( ReplyMsg ) {
(VOID) NtReplyPort( SsWinStationLpcPort,
(PPORT_MESSAGE) ReplyMsg );
}
break;
}
#endif

        /*
* Increment the number of waiting threads and wait for an LPC request
*/
WaitingApiThreads++;
RtlLeaveCriticalSection( &ApiThreadLock );
Status = NtReplyWaitReceivePort( SsWinStationLpcPort,
(PVOID *) &pContext,
(PPORT_MESSAGE) ReplyMsg,
(PPORT_MESSAGE) &ApiMsg );
RtlEnterCriticalSection( &ApiThreadLock );

        TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got a message\n" ));
/*
* If there are no more waiting threads,
* then create a new API thread to process requests.
*/
if ( --WaitingApiThreads == 0 && NumApiThreads < MaxApiThreads ) {
DWORD ThreadId;

            NumApiThreads++;
RtlLeaveCriticalSection( &ApiThreadLock );
Handle = CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)WinStationLpcThread,
NULL,
THREAD_SET_INFORMATION,
&ThreadId );

            if ( !Handle ) {
RtlEnterCriticalSection( &ApiThreadLock );
NumApiThreads--;
RtlLeaveCriticalSection( &ApiThreadLock );
} else {
NtClose( Handle );
}

        } else {
RtlLeaveCriticalSection( &ApiThreadLock );
}


if ( !NT_SUCCESS(Status) ) {
ReplyMsg = NULL;
continue;
}

        try {

            /*
* Process connection request from a new client
*/
if ( ApiMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST ) {
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got connection message\n" ));
// CONNECT_INFO is in ApiMsg from NtReplyWaitReceivePort() when
// a connection request is received. This differs from
// NtListenPort() which passes separate pointers for CONNECT_INFO.

                WinStationLpcHandleConnectionRequest( (PPORT_MESSAGE)&ApiMsg );
ReplyMsg = NULL;
continue;
}

            /*
* Process port closed message
*/
if ( ApiMsg.h.u2.s2.Type == LPC_PORT_CLOSED ) {
TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got PORT_CLOSED message pContext %p\n",
pContext));
// NOTE: This function frees the CONTEXT struct
WinStationLpcClientHasTerminated( pContext );
ReplyMsg = NULL;
continue;
}

            ASSERT(sizeof(WinStationLpcDispatch)/sizeof(WinStationLpcDispatch[0]) == SMWinStationMaxApiNumber);
ASSERT(sizeof(WinStationLpcName)/sizeof(WinStationLpcName[0]) == SMWinStationMaxApiNumber);

            /*
* Process API request from client
*/
ReplyMsg = &ApiMsg;
if ((ULONG) ApiMsg.ApiNumber >= (ULONG)SMWinStationMaxApiNumber ) {
DBGPRINT(( "TERMSRV: WinStation LPC Service Thread Bad API number %d\n",
ApiMsg.ApiNumber ));
ApiMsg.ReturnedStatus = STATUS_NOT_IMPLEMENTED;

            } else {
                TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStation LPC Service Thread got %s message\n",
WinStationLpcName[ApiMsg.ApiNumber] ));

if ( WinStationLpcDispatch[ApiMsg.ApiNumber] ) {

                    // Save Msg for use by CheckClientAccess
NtCurrentTeb()->Win32ThreadInfo = &ApiMsg;

                    // The functions set ApiMsg.ReturnedStatus
Status = (WinStationLpcDispatch[ApiMsg.ApiNumber])( pContext, &ApiMsg );

                    // Clear thread Msg pointer
NtCurrentTeb()->Win32ThreadInfo = NULL;

                } else {
// This API is not implemented in Session Manager
ApiMsg.ReturnedStatus = STATUS_NOT_IMPLEMENTED;
}

                /*
* If client does not expect a reply or reply is pending
* (will be sent asynchronously), then clear ReplyMsg pointer.
*/
if ( !ApiMsg.WaitForReply || Status == STATUS_PENDING )
ReplyMsg = NULL;
}
} except( WinStationExceptionFilter( L"WinStationLpcThread trapped!!",
GetExceptionInformation() ) ) {
ReplyMsg = NULL;
}
}

    return( STATUS_SUCCESS );
}

第三部分:

/*****************************************************************************
*
*  WinStationLpcHandleConnectionRequest
*
*   Handle connection requests and create our local data structures
*
* ENTRY:
*    ConnectionRequest (input)
*      NT LPC PORT_MESSAGE describing the request
*
* EXIT:
*   STATUS_SUCCESS - no error
*
****************************************************************************/

NTSTATUS
WinStationLpcHandleConnectionRequest(
IN PPORT_MESSAGE ConnectionRequest
)
{
NTSTATUS st;
HANDLE CommunicationPort = NULL;
BOOLEAN Accept;
PWINSTATIONAPI_CONNECT_INFO info;
REMOTE_PORT_VIEW ClientView;
REMOTE_PORT_VIEW *pClientView = NULL;
PORT_VIEW ServerView;
PORT_VIEW * pServerView = NULL;
LARGE_INTEGER SectionSize;
HANDLE PortSection = NULL ;
PWINSTATION pWinStation;
PLPC_CLIENT_CONTEXT pContext = NULL;
ULONG ClientLogonId;
PTERMSRVLPCCONTEXT pLpcContextEntry = NULL;

    TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationLpcHandleConnectionRequest called\n" ));

    Accept = TRUE; // Assume we will accept

    // An undocumented NT LPC feature is that the CONNECT_INFO structure
// follows the PORT_MESSAGE header when the connection request is
// received through NtReplyWaitReceivePort(), which is useful since we
// only have to maintain (1) thread for WinStation LPC API's, and
// do not have to dedicated one to NtListenPort() just for connection
// requests.

    if ( ConnectionRequest->u1.s1.DataLength != sizeof(WINSTATIONAPI_CONNECT_INFO) ) {
TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WSTAPI: Bad CONNECTINFO length %d\n",
ConnectionRequest->u1.s1.DataLength ));
Accept = FALSE;
} else {

        info = (PWINSTATIONAPI_CONNECT_INFO)
((ULONG_PTR)ConnectionRequest + sizeof(PORT_MESSAGE));

        //
// We can set Accept to FALSE at anytime here for certain types
// of requests and/or caller identities.
//
if ( ConnectionRequest->ClientViewSize == 0 ) {
            TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WSTAPI: Creating View memory\n" ));

            pServerView = &ServerView;

            // Setup Port memory for larger data transfers

            SectionSize.LowPart = WINSTATIONAPI_PORT_MEMORY_SIZE;
SectionSize.HighPart = 0;

            st = NtCreateSection(&PortSection, SECTION_ALL_ACCESS, NULL,
&SectionSize, PAGE_READWRITE, SEC_COMMIT, NULL);

            if (!NT_SUCCESS(st)) {
TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Error Creating Section 0x%x\n", st));
Accept = FALSE;
info->AcceptStatus = st;
} else {
ServerView.Length = sizeof(ServerView);
ServerView.SectionHandle = PortSection;
ServerView.SectionOffset = 0;
ServerView.ViewSize = SectionSize.LowPart;
ServerView.ViewBase = 0;
ServerView.ViewRemoteBase = 0;
}

        }


if ( Accept ) {
// Init the REMOTE_VIEW structure
ClientView.Length = sizeof(ClientView);
ClientView.ViewSize = 0;
ClientView.ViewBase = 0;
pClientView = &ClientView;

            info->AcceptStatus = STATUS_SUCCESS;

            if ( info->Version != CITRIX_WINSTATIONAPI_VERSION ) {
info->AcceptStatus = 1; // Fill in bad version param code
TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: WSTAPI: Bad Version %d\n", info->Version));
Accept = FALSE;
}

            // Add checks for info.RequestedAccess against the requesting
// threads security rights for WinStation access. Use the Se* stuff
// to do the checking and audit generation

            // On Security Access failure:
// Accept = FALSE;
// info->AcceptStatus = NT invalid rights message
}

    }

    //
// Get the ClientLogonId
//
if ( Accept ) {
HANDLE ClientProcessHandle = NULL;
OBJECT_ATTRIBUTES ObjA;

        InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
st = NtOpenProcess( &ClientProcessHandle, GENERIC_READ,
&ObjA, &ConnectionRequest->ClientId );

        if (NT_SUCCESS(st)) {
GetProcessLogonId( ClientProcessHandle, &ClientLogonId );
NtClose( ClientProcessHandle );
} else {
Accept = FALSE;
info->AcceptStatus = st;
}
}

    //
// Allocate a context connection control block.
// The address of this block is used as the
// port context in all calls from a client process
//

    if ( Accept ) {
pContext = MemAlloc( sizeof(LPC_CLIENT_CONTEXT) );
if ( pContext ) {
pContext->CommunicationPort = NULL;
pContext->AccessRights = info->RequestedAccess;
} else {
Accept = FALSE;
info->AcceptStatus = STATUS_NO_MEMORY;
}
}

    // More undocumented NT. Many parameters are missing here and in ntlpcapi.h
// from the documentation. The CONNECTION_INFO message is part
// of the message body following PORT_MESSAGE, just like
// NtReplyWaitReceivePort().

    TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: WSTAPI: Calling AcceptConnectPort, Accept %d\n", Accept));
TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: pContext %p, ConnectionRequest %p, info %p\n",
pContext, ConnectionRequest, info));

    if (!Accept) {
pClientView = NULL;
pServerView = NULL;
}

    st = NtAcceptConnectPort(
&CommunicationPort,
(PVOID)pContext,
ConnectionRequest,
Accept,
pServerView,
pClientView
);

    if (!NT_SUCCESS(st)) {
if (PortSection != NULL) {
NtClose(PortSection);
}
if (pContext != NULL) {
MemFree( pContext );
}
return st;
}

    // Close the PortSection (LPC will hold the reference now)
if ( pServerView )
NtClose(PortSection);

    // Insert the context before completing the connect because as soon
// as the complete is done, the client thread can send a request and 
// if this request is serviced by another LPC thread then the context
// won't be found (WinStationBrokenConnection case, by instance).

    RtlEnterCriticalSection( &ApiThreadLock );

    pLpcContextEntry = MemAlloc(sizeof(TERMSRVLPCCONTEXT)); 
if (pLpcContextEntry != NULL) {
pLpcContextEntry->pContext = pContext;
InsertTailList( &gTermsrvLpcListHead, &pLpcContextEntry->Links );
}

    // Don't leave the critical section before you complete connection. Because if context switch occurs, there 
// are chances that communication port might get distroyed and we might end up working on invalid handle. 

    if ( Accept ) {

       pContext->ClientViewBase = ClientView.ViewBase;
pContext->ClientViewBounds = (PVOID)((ULONG_PTR)ClientView.ViewBase + ClientView.ViewSize);
if ( pServerView ) {
pContext->ViewBase = ServerView.ViewBase;
pContext->ViewSize = ServerView.ViewSize;
pContext->ViewRemoteBase = ServerView.ViewRemoteBase;
           TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: ViewBase %p, ViewSize 0x%x, ViewRemoteBase %p\n",
pContext->ViewBase, pContext->ViewSize, pContext->ViewRemoteBase));

} else {
pContext->ViewBase = NULL;
pContext->ViewSize = 0;
pContext->ViewRemoteBase = NULL;
}

       pContext->ClientLogonId = ClientLogonId;

       TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: WSTAPI: Calling CompleteConnect port %p\n",CommunicationPort));
pContext->CommunicationPort = CommunicationPort;
st = NtCompleteConnectPort(CommunicationPort);

    }

    RtlLeaveCriticalSection( &ApiThreadLock );

    TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: WinStation LPC Connection %sAccepted, Logonid %d pContext %p Status 0x%x\n",
(Accept?"":"Not "), pContext->ClientLogonId, pContext, st));

    return( st );
}

第四部分:

/*****************************************************************************
*
*  WinStationGetSMCommand
*
*   This is the API that the Winstations call in order to get
*   work to do. We send Winstations commands from SendWinStationCommand()
*   once they have called this API.
*
*   NOTE: Only WinStations may call this command!
*
* ENTRY:
*    pContext (input)
*      Pointer to our context structure describing the connection.
*
*    pMsg (input/output)
*      Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
*
* EXIT:
*   STATUS_SUCCESS - no error
*
****************************************************************************/

NTSTATUS
WinStationGetSMCommand( PLPC_CLIENT_CONTEXT pContext,
PWINSTATION_APIMSG pMsg )
{
PLIST_ENTRY Head;
PWINSTATION pWinStation;
PCOMMAND_ENTRY pCommand;

    TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationGetSMCommand, LogonId=%d\n",
pContext->ClientLogonId ));

第五部分:

/*
* ICASRV WinStation LPC Dispatch Table
*
* If this table is changed, the table below must be modified too.
*/
PWINSTATION_API WinStationLpcDispatch[SMWinStationMaxApiNumber] = {

    WinStationInternalCreate,           // for ICASRV internal use only
WinStationInternalReset,            // for ICASRV internal use only
WinStationInternalDisconnect,       // for ICASRV internal use only
WinStationWCharLog,                 // for ICASRV internal use only
WinStationGetSMCommand,
WinStationBrokenConnection,
WinStationIcaReplyMessage,
WinStationIcaShadowHotkey,
NULL, // WinStationDoConnect,      // needed for connect and reconnect (I.E. InitMouse)
NULL, // WinStationDoDisconnect,   // needed for disconnect (I.E. disable screen)
NULL, // WinStationDoReconnect     // Reconnect
NULL, // WinStationExitWindows,    // Logoff
NULL, // WinStationTerminate,      // Terminate process (less gentle than logoff?)
NULL, // WinStationNtSecurity,     // CTL-ALT-DEL screen
NULL, // WinStationDoMessage,      // Message box
NULL, // WinStationDoBreakPoint    // WinStation breakpoint
NULL, // WinStationThinwireStats   // Get thinwire stats
NULL, // WinStationShadowSetup,
NULL, // WinStationShadowStart,
NULL, // WinStationShadowStop,
NULL, // WinStationShadowCleanup,
NULL, // WinStationPassthruEnable,
NULL, // WinStationPassthruDisable,
NULL, // WinStationSetTimeZone,    // Set Time Zone
NULL, // WinStationInitialProgram,
NULL, // WinStationNtsdDebug,
NULL, // WinStationBroadcastSystemMessage    // For PNP: This is the counter part to BroadcastSystemMessage on console
NULL, // WinStationSendWindowMessage                   // General Window's SendMessage() API
NULL, // SMWinStationNotify
NULL, // SMWinStationDoLoadStringNMessage
WinStationWindowInvalid
};

#if DBG
PSZ WinStationLpcName[SMWinStationMaxApiNumber] = {
"WinStationInternalCreate",
"WinStationInternalReset",
"WinStationInternalDisconnect",
"WinStationWCharLog",
    "WinStationGetSMCommand",
"WinStationBrokenConnection",
"WinStationIcaReplyMessage",
"WinStationShadowHotkey",
"WinStationDoConnect",
"WinStationDoDisconnect",
"WinStationDoReconnect",
"WinStationExitWindows",
"WinStationTerminate",
"WinStationNtSecurity",
"WinStationDoMessage",
"WinStationDoBreakPoint",
"WinStationThinwireStats",
"WinStationShadowSetup",
"WinStationShadowStart",
"WinStationShadowStop",
"WinStationShadowCleanup",
"WinStationPassthruEnable",
"WinStationPassthruDisable",
"WinStationSetTimeZone",
"WinStationInitialProgram",
"WinStationNtsdDebug",
"WinStationBroadcastSystemMessage",
"WinStationSendWindowMessage",
"SMWinStationNotify",
"SMWinStationDoLoadStringNMessage",
"WinStationWindowInvalid"
};

PSZ WinStationStateName[] = {
"Active",
"Connected",
"ConnectQuery",
"VirtualIO",
"Disconnected",
"Idle",
"Off",
"Reset",
"Down",
"Init",
};
#endif // DBG

http://www.dtcms.com/a/528594.html

相关文章:

  • 网站体验方案wordpress更改前端引用
  • vue-day01
  • LLM驱动的自动化购车顾问及评测系统
  • 现代软件工程课程 个人博客作业2-结对编程项目总结
  • Elasticsearch8.4.1升级Elasticsearch9.1.5
  • 中国中小企业网站大学生招聘就业网
  • 深度学习(3)神经网络
  • FastAPI之 SQLAIchemy
  • [人工智能-大模型-70]:模型层技术 - 从数据中自动学习一个有用的数学函数的全过程,AI函数计算三大件:神经网络、损失函数、优化器
  • 网站开发最适合的浏览器wordpress下载页插件下载
  • EN 300-2006 欧松板(OSB)检测
  • 智能优化神经网络预测
  • 【Docker】镜像仓库
  • 2.Linux指令(三)
  • 【C++】哈希表:除留余散法和哈希桶的实现
  • 沧州网站运营自己做网站需要什么材料
  • PostgreSQL查不动?分区表+覆盖索引+物化视图的优化魔法了解下?
  • 多相CFD中的模型转换:Ansys Fluent中的从DPM到VOF和欧拉壁膜
  • 关于学校的网站模板免费下载高端网站建设磐石网络好
  • 在半导体制造中如何选择最佳的刻蚀方法?
  • 构建Django的Web镜像
  • 历史数据分析——锦江酒店
  • 做网站站怎么赚钱吗企业网站推广的收获与启示
  • 大厂硬件岗位笔试题库-卷11
  • 【操作系统】408操作系统核心考点精讲:第二章——进程的概念、组成与特征​
  • 基于脉冲神经网络的语音识别系统实现:识别“将榴弹从位置幺搬到位置两“命令
  • 破茧成蝶:全方位解析Java学习难点与征服之路
  • 江门网页建站模板aws 搭建wordpress
  • C语言:使用顺序表实现通讯录
  • 手机网站与app免费的网站平台有哪些