【问题标题】:example code: A service calls CreateProcessAsUser() I want the process to run in the user's session, not session 0示例代码:服务调用 CreateProcessAsUser() 我希望进程在用户会话中运行,而不是会话 0
【发布时间】:2011-11-09 06:48:24
【问题描述】:

我正在寻找示例代码:

对于调用 CreateProcessAsUser() 的服务,我希望进程在用户会话中运行,而不是在会话 0 中运行

到目前为止,创建的进程仅像会话 0 中的服务一样运行

【问题讨论】:

    标签: windows winapi windows-7 windows-services createprocessasuser


    【解决方案1】:

    这是从一些从服务启动控制台应用程序的旧代码中删除的。它在 NT4 下工作,但我没有在现代版本的 Windows 上测试过它,所以不能保证它会像在 NT4 上一样工作。

    编辑:不,这不会按原样工作。需要添加找到here的代码来创建桌面、设置SID等

        if (!LogonUser(userId,
                       domain,
                       password,
                       LOGON32_LOGON_INTERACTIVE,
                       LOGON32_PROVIDER_DEFAULT,
                       &hUserToken))
        {
            return GetLastError();
        }
    
        if (!ImpersonateLoggedOnUser(hUserToken))
        {
            DWORD rc = GetLastError();
            CloseHandle(hUserToken);
            return rc;
        }
    
        STARTUPINFO             si;
        PROCESS_INFORMATION pi;
    
        memset(&si, 0, sizeof(si));
        memset(&pi, 0, sizeof(pi));
    
        si.cb = sizeof(si);
    
        rc = CreateProcessAsUser(hUserToken,                // user token
                               0,                           // app name
                               "foo.exe",                   // command line
                               0,                           // process attributes
                               0,                           // thread attributes
                               FALSE,                       // don't inherit handles
                               DETACHED_PROCESS,            // flags
                               0,                           // environment block
                               0,                           // current dir
                               &si,                         // startup info
                               &pi);                        // process info gets put here
    
    
        if (!rc)
        {
            DWORD rc = GetLastError();
            RevertToSelf();
            CloseHandle(hUserToken);
            return rc;
        }
    
        RevertToSelf();
        CloseHandle(hUserToken);
    
        return 0;
    

    【讨论】:

    • 您不需要创建新桌面。您在STARTUPINFO 结构中指定现有桌面,例如用户的交互式WinSta0\Default 桌面(如Microsoft 示例所示)。而且你也不需要乱搞 SID。没有它们,服务中的CreateProcessAsUser() 可以正常工作。我多年来一直在服务中使用它,没有任何问题,并且我不会为它操作 SID。另一方面,我不使用LogonUser()ImpersonateLoggedOnUser(),而是使用WTSQueryUserToken()DuplicateTokenEx()
    • 另外,您也应该在拨打CreateProcessAsUser()之前先拨打CreateEnvironmentBlock()
    • @RemyLebeau 我同意(有点)。也许你应该写一个新的答案。这是一个三年前的答案,没有接受,也没有投票,无论是赞成还是反对,所以我现在不愿意花更多时间在上面。
    • 无需复制通过WTSQueryUserToken获取的用户token。它已经返回给你一个主令牌
    【解决方案2】:

    我知道这是一篇古老的帖子,但我碰巧正在研究这个,所以这里有一些适合我的代码。

    确定当前登录用户的会话 ID

    DWORD GetCurrentSessionId ()
    {
        WTS_SESSION_INFO *pSessionInfo;
        DWORD n_sessions = 0;
        BOOL ok = WTSEnumerateSessions (WTS_CURRENT_SERVER, 0, 1, &pSessionInfo, &n_sessions);
        if (!ok)
            return 0;
    
        DWORD SessionId = 0;
    
        for (DWORD i = 0; i < n_sessions; ++i)
        {
            if (pSessionInfo [i].State == WTSActive)
            {
                SessionId = pSessionInfo [i].SessionId;
                break;
            }
        }
    
        WTSFreeMemory (pSessionInfo);
        return SessionId;
    }
    

    以当前登录用户身份启动进程

    bool LaunchProcess (const char *process_path)
    {
        DWORD SessionId = GetCurrentSessioId ();
        if (SessionId == 0)    // no-one logged in
            return false;
    
        HANDLE hToken;
        BOOL ok = WTSQueryUserToken (SessionId, &hToken);
        if (!ok)
            return false;
    
        void *environment = NULL;
        ok = CreateEnvironmentBlock (&environment, hToken, TRUE);
    
        if (!ok)
        {
            CloseHandle (hToken);
            return false;
        }
    
        STARTUPINFO si = { sizeof (si) } ;
        PROCESS_INFORMATION pi = { } ;
        si.lpDesktop = "winsta0\\default";
    
        // Do NOT want to inherit handles here
        DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT;
        ok = CreateProcessAsUser (hToken, process_path, NULL, NULL, NULL, FALSE,
            dwCreationFlags, environment, NULL, &si, &pi);
    
        DestroyEnvironmentBlock (environment);
        CloseHandle (hToken);
    
        if (!ok)
            return false;
    
        CloseHandle (pi.hThread);
        CloseHandle (pi.hProcess);
        return true;
    }
    

    【讨论】:

    • 我正面临 WTSActiveWTS_CURRENT_SERVER 的未定义错误
    • MSDN 的文档总是告诉您需要#include 哪些头文件以及需要链接哪些 .libs。抱歉,我的帖子中没有。
    • 使用我可以使用WTSQueryUserToken 令牌模拟登录用户吗?
    • 我相信ImpersonateLoggedOnUser会接受这样的令牌,是的。我建议你试一试。
    猜你喜欢
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    相关资源
    最近更新 更多