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

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

本文关键字:上下文 运行 进程 成功 ImanalogateLoggedOnUser      更新时间:2023-10-16

我有一个安装程序,在安装完成后尝试在当前用户上下文中(重新)启动我的应用程序。安装程序在 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 包含当前用户。因此,ImanalogateLoggedOnUser 是成功的。但是,如上所述,该过程是在 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

如果您阅读了 CreateProcess 的文档,您会在前三句话中找到问题的答案:

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

如果调用进程

正在模拟其他用户,则新进程将使用调用进程的令牌,而不是模拟令牌。

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