ImpersonateLoggedOnUser 成功,但初始上下文中的辅助进程仍为 运行

ImpersonateLoggedOnUser is successful but secondary process is still run in the initial context

我有一个安装程序试图在安装完成后在当前用户上下文中(重新)启动我的应用程序。 安装程序在 SYSTEM 上下文中运行,并在启动应用程序之前尝试(理论上成功)模拟当前用户。但是,当我查看任务管理器时,我看到我的应用程序在 SYSTEM 上下文中是 运行。

这是我的代码(摘自):

    TCHAR szUsername[128] = _T("");
    DWORD dwUsernameSize = 128;
    GetUserName(szUsername, &dwUsernameSize);

    // Lets the calling process impersonate the security context of a logged-on user.
    if (!ImpersonateLoggedOnUser(hToken))
    {
        throw Win32Exception(GetLastError(), _T("Failed to impersonate current user"));
    }

    TCHAR szUsername2[128] = _T("");
    DWORD dwUsernameSize2 = 128;
    GetUserName(szUsername2, &dwUsernameSize2);

    MLOGD(_T("ProcessUtils::StartProcessInCurrentUserContext: Successfully impersonated %s"), szUsername2);

    ProcessUtils::StartProcess(sExeName, lstParams, sWorkingDir, bWaitToFinish, errCode);

ProcessUtils::StartProcess 是 CreateProcess 的包装器。

szUsername 包含 SYSTEM,szUsername2 包含当前用户。所以 ImpersonateLoggedOnUser 是成功的。 但是,如上所述,该进程是在 SYSTEM 上下文中启动的,而不是当前用户。

我不确定这可能有多大帮助,但我的安装程序是用 NSIS 编写的,它通过用 C/C++ 编写的插件调用包含上面代码的函数。

有谁知道为什么我的应用程序无法在当前用户上下文中启动?

Win32 CreateProcess 在与 SYSTEM 调用者相同安全上下文中创建一个进程(即使您正在模拟)。

认为您需要调用 CreateProcessAsUser。

几年前我也遇到过类似的问题,当时我也是 处理安装程序应用程序。在经历了很多挫折之后,导致 通过在当前上下文中启动应用程序的失败尝试 用户使用CreateProcessAsUser,我终于放弃了。经过彻底的 在网上搜索,我发现了一个使用 IShellDispatch2界面。这是一个例子:

#include <Windows.h>
#include <exdisp.h>
#include <Shobjidl.h>
#include <Shlwapi.h>
#include <comutil.h>
#include <SHLGUID.h>
#include <cstdlib>
#include <iostream>

#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "comsuppw.lib")

bool ShellExecuteAsCurrentUser(const TCHAR *pcOperation, const TCHAR *pcFileName, const TCHAR *pcParameters,
    const TCHAR *pcsDirectory, const DWORD dwShow)
{
    bool bSuccess = false;

    IShellWindows *psw = NULL;
    HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));

    if(SUCCEEDED(hr))
    {
        HWND hwnd = 0;
        IDispatch* pdisp = NULL;
        _variant_t vEmpty;
        if(S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, reinterpret_cast<long*>(&hwnd), SWFO_NEEDDISPATCH, &pdisp))
        {
            if((hwnd != NULL) && (hwnd != INVALID_HANDLE_VALUE))
            {
                IShellBrowser *psb;
                hr = IUnknown_QueryService(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
                if(SUCCEEDED(hr))
                {
                    IShellView *psv = NULL;
                    hr = psb->QueryActiveShellView(&psv);
                    if(SUCCEEDED(hr))
                    {
                        IDispatch *pdispBackground = NULL;
                        HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
                        if(SUCCEEDED(hr))
                        {
                            IShellFolderViewDual *psfvd = NULL;
                            hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
                            if(SUCCEEDED(hr))
                            {
                                IDispatch *pdisp = NULL;
                                hr = psfvd->get_Application(&pdisp);
                                if(SUCCEEDED(hr))
                                {
                                    IShellDispatch2 *psd;
                                    hr = pdisp->QueryInterface(IID_PPV_ARGS(&psd));
                                    if(SUCCEEDED(hr))
                                    {
                                        _variant_t verb(pcOperation);
                                        _variant_t file(pcFileName);
                                        _variant_t para(pcParameters);
                                        _variant_t dir(pcsDirectory);
                                        _variant_t show(dwShow);
                                        if(SUCCEEDED(psd->ShellExecute(file.bstrVal, para, vEmpty, verb, show)))
                                            bSuccess = true;

                                        psd->Release();
                                        psd = NULL;
                                    }
                                    pdisp->Release();
                                    pdisp = NULL;
                                }
                            }
                            pdispBackground->Release();
                            pdispBackground = NULL;
                        }
                        psv->Release();
                        psv = NULL;
                    }
                    psb->Release();
                    psb = NULL;
                }
            }
            pdisp->Release();
            pdisp = NULL;
        }
        psw->Release();
        psw = NULL;
    }

    return bSuccess;
}

int main(int argc, char *argv[])
{
    CoInitialize(NULL);

    if(ShellExecuteAsCurrentUser(L"open", L"notepad", nullptr, nullptr, SW_SHOWNORMAL))
        std::cout << "SUCCESS" << std::endl;

    CoUninitialize();

    return 0;
}

这只是一个快速演示,实现ShellExecuteAsCurrentUser即可 通过使用 COM 接口的智能指针和一些重构改进。这个方法 在 WinXP SP3 - Win 8.1 版本上为我工作,不确定它是否适用于 Windows 10。对于 更多详细信息,请查看作者 github 页面:

https://github.com/lordmulder/stdutils/tree/master/Contrib/StdUtils

如果你读过 the documentation for CreateProcess,你会在前三句话中找到问题的答案:

Creates a new process and its primary thread. The new process runs in the security context of the calling process.

If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation token.

真的没什么好说的;您描述的行为已记录在案。如果您想以其他用户身份创建进程,则必须使用 CreateProcessAsUser 或相关函数之一。