从会话 0(服务)启动提升的用户进程 [重复]

Posted

技术标签:

【中文标题】从会话 0(服务)启动提升的用户进程 [重复]【英文标题】:Launch Elevated User Process from Session 0 (service) [duplicate] 【发布时间】:2013-12-02 09:03:54 【问题描述】:

大家早安,

这个问题似乎已被问过几次,但我找不到它是否真的可能。我已在 here

发帖

没有回复 - 让我们尝试在这里询问其他人。

我的目标是从当前用户上下文中的服务启动一个提升的进程(作为管理员)(仅当他们在本地管理员组中时)。

我可以毫无问题地获得当前用户令牌,但我无法获得该帐户的辅助/管理员令牌!

我已经阅读了很多论坛,但无法让它工作(开始认为它不可行)。

我目前的方法:

WTSGetActiveConsoleSessionId - 获取活动会话 ID WTSQueryUserToken - 获取会话 ID 的用户令牌 检查令牌是否为管理员 - 不是。 OpenProcess - 登录用户 explorer.exe 的进程句柄 OpenProcessToken - 获取访问令牌的句柄 LookupPrivilegeValue - SE_DEBUG 确认我们可以调整代币权限 DuplicateTokenEx - 用户令牌 SetTokenInformation AdjustTokenPrivileges CreateEnvironmentBlock - 运行新进程 CreateProcessAsUser - 希望在提升的用户上下文中生成进程(不会发生 - 标准用户上下文)

请参阅下面的代码 - 很抱歉它的混乱,需要整理并关闭所有句柄。目前这只是实验代码。

public static bool CreateProcessInConsoleSession(String CommandLine, bool bElevate)

    PROCESS_INFORMATION pi;
    bool isadmin = IsUserAnAdmin();

    bool bResult = false;
    uint dwSessionId, winlogonPid = 0;
    IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero,
        hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;

    Debug.Print("CreateProcessInConsoleSession");
    // Log the client on to the local computer.
    dwSessionId = WTSGetActiveConsoleSessionId();

    // Find the winlogon process
    var procEntry = new PROCESSENTRY32();

    uint hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap == INVALID_HANDLE_VALUE)
    
        return false;
    

    procEntry.dwSize = (uint)Marshal.SizeOf(procEntry); //sizeof(PROCESSENTRY32);

    if (Process32First(hSnap, ref procEntry) == 0)
    
        return false;
    

    String strCmp = "explorer.exe";
    do
    
        if (strCmp.IndexOf(procEntry.szExeFile) == 0)
        
            // We found a winlogon process...make sure it's running in the console session
            uint winlogonSessId = 0;
            if (ProcessIdToSessionId(procEntry.th32ProcessID, ref winlogonSessId) &&
                winlogonSessId == dwSessionId)
            
                winlogonPid = procEntry.th32ProcessID;
                break;
            
        
    
    while (Process32Next(hSnap, ref procEntry) != 0);

    //Get the user token used by DuplicateTokenEx
    WTSQueryUserToken(dwSessionId, ref hUserToken);

    //Check if the user token is admin
    isadmin = CheckIfAdminToken(hUserToken);

    var si = new STARTUPINFO();
    si.cb = Marshal.SizeOf(si);
    si.lpDesktop = "winsta0\\default";
    var tp = new TOKEN_PRIVILEGES();
    var luid = new LUID();
    hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);

    TOKEN_INFORMATION_CLASS tokenInfo = new TOKEN_INFORMATION_CLASS();
    uint TokenInfLength = 0 ;

    if (
        !OpenProcessToken(hProcess,
            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY
            | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ref hPToken))
    
        Debug.Print(String.Format("CreateProcessInConsoleSession OpenProcessToken error: 0",
            Marshal.GetLastWin32Error()));
    

    if (!LookupPrivilegeValue(IntPtr.Zero, SE_DEBUG_NAME, ref luid))
    
        Debug.Print(String.Format("CreateProcessInConsoleSession LookupPrivilegeValue error: 0",
            Marshal.GetLastWin32Error()));
    

    bool Result;

    #region TestToElevate
    //http://www.microsoft-questions.com/microsoft/Platform-SDK-Security/35984508/how-to-run-a-process-with-elevated-privileges-run-as-administrat.aspx
    // first call gets lenght of TokenInformation
    Result = GetTokenInformation(hPToken, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero , TokenInfLength , out TokenInfLength );
    IntPtr TokenInformation = Marshal.AllocHGlobal((int)TokenInfLength);

    Result = GetTokenInformation(hPToken, TOKEN_INFORMATION_CLASS.TokenElevation, TokenInformation, TokenInfLength, out TokenInfLength);
    if (Result == false)
        Result = GetTokenInformation(hPToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, TokenInformation, TokenInfLength, out TokenInfLength);

    isadmin = CheckIfAdminToken(hPToken);
    #endregion

    var sa = new SECURITY_ATTRIBUTES();
    sa.Length = Marshal.SizeOf(sa);

    if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa,
            (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary,
            ref hUserTokenDup))
    
        Debug.Print(
            String.Format(
                "CreateProcessInConsoleSession DuplicateTokenEx error: 0 Token does not have the privilege.",
                Marshal.GetLastWin32Error()));
        CloseHandle(hProcess);
        CloseHandle(hUserToken);
        CloseHandle(hPToken);
        return false;
    

    if (bElevate)
    
        tp.PrivilegeCount = 1;
        tp.Privileges = new int[3];
        tp.Privileges[2] = SE_PRIVILEGE_ENABLED;
        tp.Privileges[1] = luid.HighPart;
        tp.Privileges[0] = luid.LowPart;

        //Adjust Token privilege
        if (!SetTokenInformation(hUserTokenDup, TOKEN_INFORMATION_CLASS.TokenSessionId, ref dwSessionId, (uint)IntPtr.Size))
        
            Debug.Print(
                String.Format(
                    "CreateProcessInConsoleSession SetTokenInformation error: 0 Token does not have the privilege.",
                    Marshal.GetLastWin32Error()));
            CloseHandle(hProcess);
            CloseHandle(hUserToken);
            CloseHandle(hPToken);
            CloseHandle(hUserTokenDup);
            return false;
        


        if (!AdjustTokenPrivileges(hUserTokenDup, false, ref tp, Marshal.SizeOf(tp), /*(PTOKEN_PRIVILEGES)*/ IntPtr.Zero, IntPtr.Zero))
        
            int nErr = Marshal.GetLastWin32Error();
            if (nErr == ERROR_NOT_ALL_ASSIGNED)
            
                Debug.Print(String.Format(
                        "CreateProcessInConsoleSession AdjustTokenPrivileges error: 0 Token does not have the privilege.", nErr));
            
            else
            
                Debug.Print(String.Format("CreateProcessInConsoleSession AdjustTokenPrivileges error: 0", nErr));
            
        
    


    isadmin = CheckIfAdminToken(hUserTokenDup);

    //Create Environment
    uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
    IntPtr pEnv = IntPtr.Zero;
    if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
    
        dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
    
    else
    
        pEnv = IntPtr.Zero;
    


    // Launch the process in the client's logon session.
    bResult = CreateProcessAsUser(
        hUserTokenDup, // client's access token
        null, // file to execute
        CommandLine, // command line
        ref sa, // pointer to process SECURITY_ATTRIBUTES
        ref sa, // pointer to thread SECURITY_ATTRIBUTES
        false, // handles are not inheritable
        (int)dwCreationFlags, // creation flags
        pEnv, // pointer to new environment block
        null, // name of current directory
        ref si, // pointer to STARTUPINFO structure
        out pi // receives information about new process
        );
    // End impersonation of client.

    //GetLastError should be 0
    int iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();

    //Close handles task
    CloseHandle(hProcess);
    CloseHandle(hUserToken);
    CloseHandle(hUserTokenDup);
    CloseHandle(hPToken);

    return (iResultOfCreateProcessAsUser == 0) ? true : false;

【问题讨论】:

不确定您的具体问题是什么,但您可以在此处找到工作代码的完整来源:sourceforge.net/p/jedi-apilib/code/HEAD/tree/jwscl/trunk/source/… 查看函数:JwCreateProcessAsAdminUser 【参考方案1】:

你不能。服务被隔离并在与用户会话(会话 1、2、3 等)隔离的不同会话(会话 0)上运行。

【讨论】:

这是可能的。我在Delphi 中写了一些代码来做这件事,但也有很多 C# 示例:codeproject.com/articles/35773/…

以上是关于从会话 0(服务)启动提升的用户进程 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何从Windows服务启动进程到当前登录的用户会话

如何在 linux 系统上用 PHP 启动后台进程并将用户 ajax 输入重复写入其标准输入

从服务启动用户会话中的进程

从用户会话进程打开在服务中创建的 JobObject

如何检查会话是否已启动并重定向用户? [重复]

win10 登入界面显示: 本地会话管理器 服务未能登录 RPC 服务器不可用 随后一直重启重复