添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Hi Team,

I am using the advapi32.dll to consume CreateProcessAsUser to launch the ui exe(UIAccess=true) in user context.
But i am getting elevated permission required exception..
I googled it and found that we need to use SetTokenInformation to make it work for uiaccesss=true exe's.

Could you please guide me how to do it..?

Below is my current code..

public Process StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
// APIs below will fail if it is not running in session 0
//if (Process.GetCurrentProcess().SessionId != 0)
// return null;

        var userToken = IntPtr.Zero;  
        var startInfo = new NativeStructsNew.STARTUPINFO();  
        var procInfo = new NativeStructsNew.PROCESS_INFORMATION();  
        var environmentHandler = IntPtr.Zero;  
        Process result = null;  
        startInfo.cb = Marshal.SizeOf(typeof(NativeStructsNew.STARTUPINFO));  
            if (!GetActiveSessionUserToken(out userToken))  
                throw new Exception($"{nameof(StartProcessAsCurrentUser)} - {nameof(GetActiveSessionUserToken)} failed.");  
            int dwCreationFlags = NativeConsts.CREATE_UNICODE_ENVIRONMENT | (visible ? NativeConsts.CREATE_NEW_CONSOLE : NativeConsts.CREATE_NO_WINDOW);  
            startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);  
            startInfo.lpDesktop = "winsta0\\default";  
            if (!NativeMethodsNew.CreateEnvironmentBlock(ref environmentHandler, userToken, false))  
                int errorCode = Marshal.GetLastWin32Error();  
                throw new Exception($"{nameof(StartProcessAsCurrentUser)} - {nameof(NativeMethodsNew.CreateEnvironmentBlock)} failed. GetLastError = {errorCode}");  
            var sa = new NativeStructsNew.SECURITY_ATTRIBUTES();  
            sa.Length = Marshal.SizeOf(sa);  
            var ta = new NativeStructsNew.SECURITY_ATTRIBUTES();  
            ta.Length = Marshal.SizeOf(ta);  
            if (!NativeMethodsNew.CreateProcessAsUser(userToken, appPath, cmdLine, ref sa, ref ta, false,  
                    dwCreationFlags, environmentHandler, workDir, ref startInfo, out procInfo))  
                int errorCode = Marshal.GetLastWin32Error();  
                throw new Exception($"{nameof(StartProcessAsCurrentUser)} - CreateProcessAsUser failed. GetLastError = {errorCode}");  
            uint pid = procInfo.dwProcessId;  
            result = Process.GetProcessById((int)pid);  
        catch (Exception)  
            // The process does not exist  
            result = null;  
        finally  
            if (userToken != IntPtr.Zero)  
                NativeMethodsNew.CloseHandle(userToken);  
            if (environmentHandler != IntPtr.Zero)  
                NativeMethodsNew.DestroyEnvironmentBlock(environmentHandler);  
            if (procInfo.hThread != IntPtr.Zero)  
                NativeMethodsNew.CloseHandle(procInfo.hThread);  
            if (procInfo.hProcess != IntPtr.Zero)  
                NativeMethodsNew.CloseHandle(procInfo.hProcess);  
        return result;  

---------
private static UInt32 GetActiveConsoleSessionId()
IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
uint activeSessionId = Platform.NoUserSession;
IntPtr infoSessionsHandler = IntPtr.Zero;
int sessionsCount = 0;

            if (NativeMethodsNew.WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref infoSessionsHandler, ref sessionsCount))  
                Int32 dataSize = Marshal.SizeOf(typeof(NativeStructsNew.WTS_SESSION_INFO));  
                IntPtr current = infoSessionsHandler;  
                for (int i = 0; i < sessionsCount; i++)  
                    var si = (NativeStructsNew.WTS_SESSION_INFO)Marshal.PtrToStructure(current, typeof(NativeStructsNew.WTS_SESSION_INFO));  
                    if (WTS_CONNECTSTATE_CLASS.WTSActive == si.State)  
                        activeSessionId = si.SessionID;  
                        break;  
                    current += dataSize;  
                if (infoSessionsHandler != IntPtr.Zero)  
                    NativeMethodsNew.WTSFreeMemory(infoSessionsHandler);  
            return activeSessionId;  
        catch (Exception ex)  
            Debug.WriteLine("exception in GetActiveConsoleSessionId - {0}", ex);  
        return Platform.NoUserSession;  
    public uint GetActiveUserSessionId()  
        return GetActiveConsoleSessionId();  
    public bool GetActiveSessionUserToken(out IntPtr userToken)  
        userToken = IntPtr.Zero;  
        bool result = false;  
        IntPtr userTokenHandle = IntPtr.Zero;  
            // Get active user session id by enumerating through the sessions  
            uint activeSessionId = GetActiveUserSessionId();  
            // If enumerating did not work, fall back to the old method  
            if (activeSessionId == NativeConsts.INVALID_SESSION_ID)  
                activeSessionId = NativeMethodsNew.WTSGetActiveConsoleSessionId();  
            // Get the primary access token of the logged-on user specified by the session ID  
            if (activeSessionId != NativeConsts.INVALID_SESSION_ID  
                && NativeMethodsNew.WTSQueryUserToken(activeSessionId, out userTokenHandle) != 0)  
                var ta = new NativeStructsNew.SECURITY_ATTRIBUTES();  
                ta.Length = Marshal.SizeOf(ta);  
                // Convert the impersonation token to a primary token  
                result = NativeMethodsNew.DuplicateTokenEx(userTokenHandle, 0, ref ta,  
                    (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,  
                    out userToken);  
                NativeMethodsNew.SetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenUIAccess, 0, (UInt32)IntPtr.Size);  
        finally  
            if (userTokenHandle != IntPtr.Zero)  
                NativeMethodsNew.CloseHandle(userTokenHandle);  
        return result;  
						
     NativeMethodsNew.SetTokenInformation(userToken, TOKEN_INFORMATION_CLASS.TokenUIAccess, 0, (UInt32)IntPtr.Size);  

I see two issues in this line of code --

If you want to set the UIAccess flag in the token you must pass 1 instead of 0. The docs describing TokenUIAccess say "The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set." In 64-bit code IntPtr.Size will be 8 bytes, but the TokenUIAccess should be set with a 4 byte value. It appears that in 64 bit code the function passes the wrong size information. Use uint instead of IntPtr to always work with a 4 byte value.

Un WPF UI exe which i am trying to launch has below
<requestedExecutionLevel level="asInvoker" uiAccess="true" />

SerTokenInformation method with api in NativeMethodnew class.

The Below code is where i am calling SetTokenInformation.

Still i am getting the same issue.. Please assist me the correct code..