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

时间:2016-03-07 10:41:09

标签: c++ winapi impersonation

我有一个安装程序,在安装完成后尝试(重新)在当前用户上下文中启动我的应用程序。 安装程序在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 ++编写的插件调用包含上面代码的函数。

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

3 个答案:

答案 0 :(得分:3)

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

认为您需要调用CreateProcessAsUser。

答案 1 :(得分:2)

几年前,当我也是这样时,我遇到了一个非常类似的问题 处理安装程序应用程序。经过很多挫折,造成了 失败的尝试在当前的上下文中启动应用程序 用户使用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

答案 2 :(得分:1)

如果您已阅读the documentation for CreateProcess,您可以在前三个句子中找到问题的答案:

  

创建一个新进程及其主线程。新进程在调用进程的安全上下文中运行。

     

如果调用进程模仿其他用户,则新进程将使用该令牌进行调用,而不是模拟令牌。

真的没有什么可说的;您描述的行为是记录在案的。如果要以其他用户身份创建流程,则必须使用CreateProcessAsUser或其中一个相关功能。