WTSGetActiveConsoleSessionId返回系统会话

WTSGetActiveConsoleSessionId returning system session(WTSGetActiveConsoleSessionId返回系统会话)
本文介绍了WTSGetActiveConsoleSessionId返回系统会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个曾经发生过的问题,但我仍然不知道如何修复它。我有一个windows服务,当服务运行时,它首先需要模拟登录的用户(活动用户)来加载保存在用户的应用程序数据文件夹中的一些路径和设置。每次新用户登录windows时,我使用的代码都能很好地工作,除了一次服务错误地模拟了系统会话,而不是Actie会话。正如我所说,这种情况只发生过一次,但我真的不知道为什么。

这是我检查活动会话的方式以及模拟是如何完成的:

首先,当服务检测到登录事件时,它通过调用查询活动会话ID

WTSGetActiveConsoleSessionId();

然后,它通过调用WTSQuerySessionInformation检查会话是否处于活动状态(已连接),如下所示:

WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;

DWORD bytes_returned = 0;
if (::WTSQuerySessionInformation(
    WTS_CURRENT_SERVER_HANDLE,
    session_id,
    WTSConnectState,
    reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
    &bytes_returned)) 
{
        ASSERT(bytes_returned == sizeof(*ptr_wts_connect_state));
        wts_connect_state = *ptr_wts_connect_state;
        ::WTSFreeMemory(ptr_wts_connect_state);
        return (WTSActive == wts_connect_state); 
}

其中session_id是WTSGetActiveConsoleSessionId()返回的会话ID。

然后我使用WTSQueryUserToken

查询用户令牌

如果成功,则服务调用GetTokenInformation如下所示:

DWORD neededSize = 0;
    HANDLE *realToken = new HANDLE;
    if(GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize))
    {
        CloseHandle(hImpersonationToken);
        hImpersonationToken = *realToken;
    }

其中hImpersonationToken是从GetTokenInformation检索的令牌

如果上述操作均成功,则调用

DuplicateTokenEx( hImpersonationToken,
                                0,
                                NULL,
                                SecurityImpersonation,
                                TokenPrimary,
                                phUserToken );

        CloseHandle( hImpersonationToken );

如果成功,则使用检索到的令牌进行模拟

ImpersonateLoggedOnUser(phUserToken);

我的服务将写入日志文件,并且根据该日志,在模拟之后,服务加载了系统配置文件,而不是用户。

如果之前的所有调用都成功了,则该服务会加载系统配置文件,而不是用户。

现在,此问题在我重新启动计算机时发生过一次,但我甚至没有再次复制它,并且我已经尝试了数周。

我不确定系统配置文件会话如何可能是活动会话。我只想知道我是否做错了什么,不确定我在查询会话信息时是否使用了错误的INFO类。

我还想知道是否可以在使用返回的令牌模拟之前确定查询的会话是否实际上是系统会话,以便可以再次尝试模拟?

正如我所说,在进入下一步之前,所有提到的调用都检查了它们的返回对象和代码,因此它们不会有任何来自调用的错误,因为它不应该继续进行模拟,但是它确实发生了:(

如果有任何可能的帮助,我将不胜感激.谢谢。

推荐答案

WTSGetActiveConsoleSessionId()在从服务运行时可能实际返回会话0,具体取决于它运行的Windows版本。

执行所需操作的方法是枚举所有会话,找到已连接的会话(会话0断开连接),然后模拟该会话的用户。下面的代码在我的盒子上运行良好。

//Function to run a process as active user from windows service
void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args)
{
    DWORD session_id = -1;
    DWORD session_count = 0;

    WTS_SESSION_INFOA *pSession = NULL;


    if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count))
    {
        //log success
    }
    else
    {
        //log error
        return;
    }

    for (int i = 0; i < session_count; i++)
    {
        session_id = pSession[i].SessionId;

        WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
        WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;

        DWORD bytes_returned = 0;
        if (::WTSQuerySessionInformation(
            WTS_CURRENT_SERVER_HANDLE,
            session_id,
            WTSConnectState,
            reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
            &bytes_returned))
        {
            wts_connect_state = *ptr_wts_connect_state;
            ::WTSFreeMemory(ptr_wts_connect_state);
            if (wts_connect_state != WTSActive) continue;
        }
        else
        {
            //log error
            continue;
        }

        HANDLE hImpersonationToken;

        if (!WTSQueryUserToken(session_id, &hImpersonationToken))
        {
            //log error
            continue;
        }


        //Get real token from impersonation token
        DWORD neededSize1 = 0;
        HANDLE *realToken = new HANDLE;
        if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1))
        {
            CloseHandle(hImpersonationToken);
            hImpersonationToken = *realToken;
        }
        else
        {
            //log error
            continue;
        }


        HANDLE hUserToken;

        if (!DuplicateTokenEx(hImpersonationToken,
            //0,
            //MAXIMUM_ALLOWED,
            TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED,
            NULL,
            SecurityImpersonation,
            TokenPrimary,
            &hUserToken))
        {
            //log error
            continue;
        }

        // Get user name of this process
        //LPTSTR pUserName = NULL;
        WCHAR* pUserName;
        DWORD user_name_len = 0;

        if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len))
        {
            //log username contained in pUserName WCHAR string
        }

        //Free memory                         
        if (pUserName) WTSFreeMemory(pUserName);

        ImpersonateLoggedOnUser(hUserToken);

        STARTUPINFOW StartupInfo;
        GetStartupInfoW(&StartupInfo);
        StartupInfo.cb = sizeof(STARTUPINFOW);
        //StartupInfo.lpDesktop = "winsta0\default";

        PROCESS_INFORMATION processInfo;

        SECURITY_ATTRIBUTES Security1;
        Security1.nLength = sizeof SECURITY_ATTRIBUTES;

        SECURITY_ATTRIBUTES Security2;
        Security2.nLength = sizeof SECURITY_ATTRIBUTES;

        void* lpEnvironment = NULL;

        // Get all necessary environment variables of logged in user
        // to pass them to the new process
        BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE);
        if (!resultEnv)
        {
            //log error
            continue;
        }

        WCHAR PP[1024]; //path and parameters
        ZeroMemory(PP, 1024 * sizeof WCHAR);
        wcscpy(PP, path);
        wcscat(PP, L" ");
        wcscat(PP, args);

        // Start the process on behalf of the current user 
        BOOL result = CreateProcessAsUserW(hUserToken, 
            NULL,
            PP,
            //&Security1,
            //&Security2,
            NULL,
            NULL,
            FALSE, 
            NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
            //lpEnvironment,
            NULL,
            //"C:\ProgramData\some_dir",
            NULL,
            &StartupInfo,
            &processInfo);

        if (!result)
        {
            //log error
        }
        else
        {
            //log success
        }

        DestroyEnvironmentBlock(lpEnvironment);

        CloseHandle(hImpersonationToken);
        CloseHandle(hUserToken);
        CloseHandle(realToken);

        RevertToSelf();
    }

    WTSFreeMemory(pSession);
}

这篇关于WTSGetActiveConsoleSessionId返回系统会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

windeployqt doesn#39;t deploy qwindowsd.dll for a debug application(windeployqt不会为调试应用程序部署qwindowsd.dll)
QLineEdit: Show a processed text, not the entered one, but keep it (custom echo mode)(QLineEdit:显示已处理的文本,而不是输入的文本,但保留它(自定义回显模式))
Showing tooltip in a Qt chart with multiple y axes(在带有多个y轴的Qt图表中显示工具提示)
QTableView, how to change dragging multiple items display(QTableView,如何更改拖动多项显示)
How can I build Qt 5.13.2 with GCC 11.1 on Windows?(如何在Windows上用GCC 11.1构建Qt 5.13.2?)
singleton template as base class in C++(C++中作为基类的Singleton模板)