CreateProcessAsUser 生成错误 5

Posted

技术标签:

【中文标题】CreateProcessAsUser 生成错误 5【英文标题】:CreateProcessAsUser generating error 5 【发布时间】:2015-09-17 19:39:14 【问题描述】:

我尝试混合使用代码 here 和 here 从通过 QtService 初始化的服务运行 GUI exe,但是每当我运行下面的代码时,我都会从 CreateProcessAsUser 收到错误 5。

另外,我看到了类似问题的答案here on ***,但无法弄清楚 DACL 与问题的关系,并且无法使用 Harry Johnson 的答案,因为我没有登录信息来自用户。

那么,谁能帮我理解为什么我从下面的代码中收到错误 5(拒绝访问)?

if(initUiWin())
    log->write("InitUiWin executed.");
else 
    QString errorNumber = QString::number(GetLastError());
    log->write("InitUiWin error: " + errorNumber);

-

bool initUiWin()

    // obtain the currently active session id; every logged on
    // User in the system has a unique session id
    uint dwSessionId = WTSGetActiveConsoleSessionId();

    // obtain the process id of the winlogon process that
    // is running within the currently active session
    QString processName("winlogon.exe");
    DWORD winlogonPID = FindProcessId(processName.toStdWString(),dwSessionId);
    if( winlogonPID != 0 ) 
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, winlogonPID);
    HANDLE hToken;
    OpenProcessToken(hProcess,TOKEN_READ,&hToken);

    // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
    SECURITY_ATTRIBUTES sa;
    sa.nLength = static_cast<DWORD>(sizeof(SECURITY_ATTRIBUTES));

    // copy the access token of the winlogon process;
    // the newly created token will be a primary token
    HANDLE hUserTokenDup;
    if (!DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,&sa,
                            SecurityIdentification,TokenPrimary,&hUserTokenDup)) 
        CloseHandle(hProcess);
        CloseHandle(hToken);
        return false;
    

    // Get Handle to the interactive window station
    HWINSTA hwinsta = NULL;
    hwinsta = OpenWindowStation(
           _T(L"winsta0"),                   // the interactive window station
           FALSE,                       // handle is not inheritable
           READ_CONTROL | WRITE_DAC);   // rights to read/write the DACL
    if(hwinsta == NULL)
        return false;

    // To get the correct default desktop, set the caller's
    // window station to the interactive window station.
    if (!SetProcessWindowStation(hwinsta))
        return false;

    // Get a handle to the interactive desktop.
    HDESK hdesk = NULL;
    hdesk = OpenDesktop(
          _T(L"default"),     // the interactive window station
          0,             // no interaction with other desktop processes
          FALSE,         // handle is not inheritable
          READ_CONTROL | // request the rights to read and write the DACL
          WRITE_DAC |
          DESKTOP_WRITEOBJECTS |
          DESKTOP_READOBJECTS);
    if(hdesk == NULL)
        return false;

    // Get the SID for the client's logon session.
    PSID pSid = NULL;
    if (!GetLogonSID(hUserTokenDup, &pSid))
          return false;

    // Allow logon SID full access to interactive window station.
    if (!AddAceToWindowStation(hwinsta, pSid) )
          return false;

    // Allow logon SID full access to interactive desktop.
    if (!AddAceToDesktop(hdesk, pSid) )
          return false;

    // Impersonate client to ensure access to executable file.
    if (!ImpersonateLoggedOnUser(hUserTokenDup) )
          return false;

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = static_cast<DWORD>(sizeof(STARTUPINFO));

    // interactive window station parameter; basically this indicates
    // that the process created can display a GUI on the desktop
    wchar_t auxBuffer[16] = L"winsta0\\default";
    si.lpDesktop = auxBuffer;

    // flags that specify the priority and creation method of the process
    int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB;

    // create a new process in the current User's logon session
    bool result = CreateProcessAsUser(hUserTokenDup,  // client's access token
                                    L"test-ui-systray.exe",             // file to execute
                                    NULL,  // command line
                                    &sa,           // pointer to process SECURITY_ATTRIBUTES
                                    &sa,           // pointer to thread SECURITY_ATTRIBUTES
                                    false,            // handles are not inheritable
                                    dwCreationFlags,  // creation flags
                                    NULL,      // pointer to new environment block
                                    NULL,             // name of current directory
                                    &si,           // pointer to STARTUPINFO structure
                                    &pi      // receives information about new process
                                    );

    if (pSid)
          FreeLogonSID(&pSid);
    if (hdesk)
          CloseDesktop(hdesk);
    if (hwinsta)
          CloseWindowStation(hwinsta);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    return result;


return false;


【问题讨论】:

如果某个函数(如CreateProcessAsUser)失败,您应该在该点调用GetLastError()并保存错误代码。目前您正在调用其他函数,如CloseDesktopCloseWindowStation 等,所有这些都可能与GetLastError() 返回的错误代码相混淆。 您的服务是否以LocalSystem 运行?如果是这样,MSDN 文章非常清楚该怎么做。 (WTSQueryUserToken (WTSGetActiveConsoleSessionId (), &amp;hToken); 然后CreateProcessAsUser(hToken, ...)如果您不是以LocalSystem 运行,那么“没有合法 方法来获取具有正确会话ID 的登录用户令牌”。 更改窗口站和桌面权限的逻辑错误 - 该代码更改了您的窗口站和桌面上的权限,而不是用户的窗口站和桌面上的权限会议。但在这种情况下,您无论如何都不需要更改权限。您确定是 CreateProcessAsUser 失败而不是其他功能之一吗? 最明显的问题是sa没有初始化。 我认为这是为@JonathanPotter 准备的。我在问您的服务是否以LocalSystem 运行。 【参考方案1】:

把它放在这里是为了可见性。 HarryJohnston 在 cmets 中回答。问题是 OpenProcessToken 中的标志,我刚刚更改了

OpenProcessToken(hProcess,TOKEN_READ,&hToken)

OpenProcessToken(hProcess,TOKEN_READ|TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,&hToken)

【讨论】:

以上是关于CreateProcessAsUser 生成错误 5的主要内容,如果未能解决你的问题,请参考以下文章

CreateProcessAsUser 在活动会话中创建窗口

CreateProcessAsUser hToken 为零

无密码的 CreateProcessAsUser 和 LogonUser

CreateProcessAsUser 进程以 -1073741502 退出

从 Vista 上的服务中使用 CreateProcessAsUser 的桌面问题

“更改用户”时 CreateProcessAsUser 不起作用