none
RunAs Admin RRS feed

  • Question

  • I have a admin user and when I start a process with that credencias The process is not with admin powers.

     Dim process As Process = Nothing
            Dim processStartInfo As ProcessStartInfo
    
            processStartInfo = New ProcessStartInfo With {
                .FileName = "notepad.exe",
                .Arguments = "",
                .WindowStyle = ProcessWindowStyle.Normal,
                .UseShellExecute = False,
                .UserName = "admin",
                .Domain = "INDRACPS040",
                .Password = TosecureString("123123"),
                .WorkingDirectory = "C:\WINDOWS\system32",
                .LoadUserProfile = True
            }

    


    Tuesday, October 8, 2019 1:27 PM

Answers

  • The code posted above appears as if it was intended to be executed from an interactive console application.

    You need to code and test for a Windows Service running as SYSTEM and provide for the fact that the elevated process you intend to start will not display a user interface.

    Further, the code does not call GetTokenInformation to obtain the linked token for a member of the Administrators group that will be used to start an elevated process.  There should not be a need to call DuplicateToken.

    For demo purposes I used the C# Windows service still available from A basic Windows service in C# (CSWindowsService)

    I added the following to the service so that it would use a thread to start the target process and then wait for it to complete so that it could unload the user profile and do other cleanup.  The service can be instructed to start the process from a command prompt by using the sc command -- "sc control CSWindowsService 142".  This allows you to attach a debugger to the service after it has started and set a breakpoint that will be hit when the worker thread is started.  While the sample code does do some checking on the results of Windows API function calls, it does not include all possible error checking and exception handling that might be appropriate.

            protected override void OnCustomCommand(int command)
            {
                if(command == 142)
                    ThreadPool.QueueUserWorkItem(new WaitCallback(StartProc));
            }
    
            private void StartProc(object state)
            {
                try
                {
                    IntPtr hToken;
    
                    if (Win32.LogonUser("Infra", "TEST", "test", Win32.LOGON32_LOGON_INTERACTIVE, Win32.LOGON32_PROVIDER_DEFAULT, out hToken))
                    {
                        int len = Marshal.SizeOf<Win32.TOKEN_LINKED_TOKEN>();
                        int retlen;
                        IntPtr tlt = Marshal.AllocHGlobal(len);
    
                        if (Win32.GetTokenInformation(hToken, Win32.TOKEN_INFORMATION_CLASS.TokenLinkedToken, tlt, len, out retlen))
                        {
                            Win32.TOKEN_LINKED_TOKEN linked = Marshal.PtrToStructure<Win32.TOKEN_LINKED_TOKEN>(tlt);
                            Win32.PROFILEINFO profinfo = new Win32.PROFILEINFO();
    
                            profinfo.dwSize = Marshal.SizeOf<Win32.PROFILEINFO>();
                            profinfo.lpUserName = "Infra";
                            if (Win32.LoadUserProfile(linked.LinkedToken, ref profinfo))
                            {
                                IntPtr pEnvironment;
                                if (Win32.CreateEnvironmentBlock(out pEnvironment, linked.LinkedToken, false))
                                {
                                    Win32.PROCESS_INFORMATION pi;
                                    Win32.STARTUPINFO si = new Win32.STARTUPINFO();
                                    Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
    
                                    sa.nLength = Marshal.SizeOf<Win32.SECURITY_ATTRIBUTES>();
                                    si.cb = Marshal.SizeOf<Win32.STARTUPINFO>();
    
                                    bool bImpersonating = Win32.ImpersonateLoggedOnUser(linked.LinkedToken);
    
                                    if (Win32.CreateProcessAsUser(linked.LinkedToken,
                                        @"C:\Users\RLWA32\Documents\Visual Studio 2015\Projects\TokenLister\Debug\TokenLister.exe",
                                        string.Empty, ref sa, ref sa, false, Win32.CREATE_UNICODE_ENVIRONMENT,
                                        pEnvironment, @"C:\Temp", ref si, out pi))
                                    {
                                        uint exitCode;
    
                                        Win32.CloseHandle(pi.hThread);
                                        Win32.WaitForSingleObject(pi.hProcess, Win32.INFINITE);
                                        Win32.GetExitCodeProcess(pi.hProcess, out exitCode);
                                        Win32.CloseHandle(pi.hProcess);
    
                                        string strMsg = "Process TokenLister.exe terminated with return code " + exitCode.ToString();
                                        this.eventLog1.WriteEntry(strMsg, EventLogEntryType.Information);
                                    }
                                    else
                                    {
                                        int err = Marshal.GetLastWin32Error();
                                        string strError = "CreateProcessAsUser failed with error code " + err.ToString();
                                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                    }
    
                                    if (bImpersonating)
                                        Win32.RevertToSelf();
    
                                    Win32.DestroyEnvironmentBlock(pEnvironment);
                                }
                                else
                                {
                                    int err = Marshal.GetLastWin32Error();
                                    string strError = "CreateEnvironmentBlock failed with error code " + err.ToString();
                                    this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                }
    
                                Win32.UnloadUserProfile(linked.LinkedToken, profinfo.hProfile);
                            }
                            else
                            {
                                int err = Marshal.GetLastWin32Error();
                                string strError = "LoadUserProfile failed with error code " + err.ToString();
                                this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                            }
    
                            Win32.CloseHandle(linked.LinkedToken);
                        }
                        else
                        {
                            int err = Marshal.GetLastWin32Error();
                            string strError = "GetTokenInformation failed with error code " + err.ToString();
                            this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                        }
    
                        Marshal.FreeHGlobal(tlt);
    
                        Win32.CloseHandle(hToken);
                    }
                    else
                    {
                        int err = Marshal.GetLastWin32Error();
                        string strError = "LogonUser failed with error code " + err.ToString();
                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                    }
                }
                catch (Exception ex)
                {
                    string strExeption = "Caught exception : " + ex.Message;
                    this.eventLog1.WriteEntry(strExeption, EventLogEntryType.Error);
                }
            }
    
    

    The sample code above executes a process that writes information obtained from its token to a file.  When executed from the C# service, it produced the following output -

    Current Directory is C:\Temp
    Account Name is Infra
    High Integrity Process
    Session ID from Token is 0
    Token Has Elevated Privileges
    Token is an Elevated token
    Token is a Primary token
    

    This is the Win32 class that I used for the Windows API -

        public class Win32
        {
            public const int LOGON32_LOGON_INTERACTIVE = 2;
            public const int LOGON32_LOGON_NETWORK = 3;
            public const int LOGON32_LOGON_BATCH = 4;
            public const int LOGON32_LOGON_SERVICE = 5;
            public const int LOGON32_LOGON_UNLOCK = 7;
            public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
            public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
    
            public const int LOGON32_PROVIDER_DEFAULT = 0;
            public const int LOGON32_PROVIDER_WINNT35 = 1;
            public const int LOGON32_PROVIDER_WINNT40 = 2;
            public const int LOGON32_PROVIDER_WINNT50 = 3;
            public const int LOGON32_PROVIDER_VIRTUAL = 4;
    
            public const int DEBUG_PROCESS = 0x00000001;
            public const int DEBUG_ONLY_THIS_PROCESS = 0x00000002;
            public const int CREATE_SUSPENDED = 0x00000004;
            public const int DETACHED_PROCESS = 0x00000008;
    
            public const int CREATE_NEW_CONSOLE = 0x00000010;
            public const int NORMAL_PRIORITY_CLASS = 0x00000020;
            public const int IDLE_PRIORITY_CLASS = 0x00000040;
            public const int HIGH_PRIORITY_CLASS = 0x00000080;
    
            public const int REALTIME_PRIORITY_CLASS = 0x00000100;
            public const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
            public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
            public const int CREATE_SEPARATE_WOW_VDM = 0x00000800;
    
            public const int CREATE_SHARED_WOW_VDM = 0x00001000;
            public const int CREATE_FORCEDOS = 0x00002000;
            public const int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000;
            public const int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000;
    
            public const int INHERIT_PARENT_AFFINITY = 0x00010000;
            public const int INHERIT_CALLER_PRIORITY = 0x00020000;    // Deprecated
            public const int CREATE_PROTECTED_PROCESS = 0x00040000;
            public const int EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
    
            public const int PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000;
            public const int PROCESS_MODE_BACKGROUND_END = 0x00200000;
    
            public const int CREATE_BREAKAWAY_FROM_JOB = 0x01000000;
            public const int CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000;
            public const int CREATE_DEFAULT_ERROR_MODE = 0x04000000;
            public const int CREATE_NO_WINDOW = 0x08000000;
    
            public const uint INFINITE = 0xFFFFFFFF;
    
    
            [StructLayout(LayoutKind.Sequential)]
            public struct PROFILEINFO
            {
                public int dwSize;
                public int dwFlags;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpUserName;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpProfilePath;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpDefaultPath;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpServerName;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpPolicyPath;
                public IntPtr hProfile;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct TOKEN_LINKED_TOKEN
            {
                public IntPtr LinkedToken;
            }
    
            public enum TOKEN_INFORMATION_CLASS
            {
                TokenUser = 1,
                TokenGroups,
                TokenPrivileges,
                TokenOwner,
                TokenPrimaryGroup,
                TokenDefaultDacl,
                TokenSource,
                TokenType,
                TokenImpersonationLevel,
                TokenStatistics,
                TokenRestrictedSids,
                TokenSessionId,
                TokenGroupsAndPrivileges,
                TokenSessionReference,
                TokenSandBoxInert,
                TokenAuditPolicy,
                TokenOrigin,
                TokenElevationType,
                TokenLinkedToken,
                TokenElevation,
                TokenHasRestrictions,
                TokenAccessInformation,
                TokenVirtualizationAllowed,
                TokenVirtualizationEnabled,
                TokenIntegrityLevel,
                TokenUIAccess,
                TokenMandatoryPolicy,
                TokenLogonSid,
                TokenIsAppContainer,
                TokenCapabilities,
                TokenAppContainerSid,
                TokenAppContainerNumber,
                TokenUserClaimAttributes,
                TokenDeviceClaimAttributes,
                TokenRestrictedUserClaimAttributes,
                TokenRestrictedDeviceClaimAttributes,
                TokenDeviceGroups,
                TokenRestrictedDeviceGroups,
                TokenSecurityAttributes,
                TokenIsRestricted,
                TokenProcessTrustLevel,
                TokenPrivateNameSpace,
                TokenSingletonAttributes,
                MaxTokenInfoClass  // MaxTokenInfoClass should always be the last enum
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SECURITY_ATTRIBUTES
            {
                public int nLength;
                public IntPtr lpSecurityDescriptor;
                public int bInheritHandle;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            public struct STARTUPINFO
            {
                public int cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public uint dwX;
                public uint dwY;
                public uint dwXSize;
                public uint dwYSize;
                public uint dwXCountChars;
                public uint dwYCountChars;
                public uint dwFillAttribute;
                public uint dwFlags;
                public ushort wShowWindow;
                public ushort cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public uint dwProcessId;
                public uint dwThreadId;
            }
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool LogonUser(string user, string domain, string password, uint type, uint provider, out IntPtr hToken);
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CloseHandle(IntPtr handle);
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            public static extern uint WaitForSingleObject(IntPtr handle, uint dwMilliseconds);
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetExitCodeProcess(IntPtr handle, out uint exitCode);
    
            [DllImport("userenv.dll",  CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);
    
            [DllImport("userenv.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile);
    
            [DllImport("userenv.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
    
            [DllImport("userenv.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
                                                          IntPtr TokenInformation, int TokenInformationLength, out int ReturnLength);
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool ImpersonateLoggedOnUser(IntPtr TokenHandle);
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool RevertToSelf();
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CreateProcessAsUser(
                IntPtr hToken,
                string lpApplicationName,
                string lpCommandLine,
                ref SECURITY_ATTRIBUTES lpProcessAttributes,
                ref SECURITY_ATTRIBUTES lpThreadAttributes,
                bool bInheritHandles,
                uint dwCreationFlags,
                IntPtr lpEnvironment,
                string lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);
    
        }
    

    • Proposed as answer by RLWA32 Friday, October 11, 2019 9:32 AM
    • Marked as answer by Ran-jj Friday, October 11, 2019 12:58 PM
    Thursday, October 10, 2019 10:55 AM

All replies

  • Notepad is started as Admin if I do :

    using (Process p = new Process())
    {
        p.StartInfo.Verb = "runas";
        p.StartInfo.FileName = "notepad.exe";
        p.Start();
    }

    Tuesday, October 8, 2019 2:26 PM
  • not working
    Tuesday, October 8, 2019 2:39 PM
  • On Windows 10, Task Manager shows that it is elevated :

    Tuesday, October 8, 2019 2:50 PM
  • Ok, but when I pass the credencias of my admin user the notepad is not elevated

    Tuesday, October 8, 2019 3:00 PM
  • Are you making sure to use ShellExecute?  Verb is "runas"?
    • Edited by RLWA32 Tuesday, October 8, 2019 3:32 PM
    Tuesday, October 8, 2019 3:31 PM
  •  Dim process As Process = Nothing
            Dim processStartInfo As ProcessStartInfo
    
            processStartInfo = New ProcessStartInfo With {
                .Verb = "runas",
                .FileName = "notepad.exe",
                .Arguments = "",
                .WindowStyle = ProcessWindowStyle.Normal,
                .UseShellExecute = False,
                .UserName = "Infra",
                .Domain = "INDRACPS040",
                .Password = TosecureString("Indra!@123"),
                .WorkingDirectory = "C:\WINDOWS\system32",
                .LoadUserProfile = True
            }
    
            Try
                process = Process.Start(processStartInfo)           
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Finally
    
                If Not (process Is Nothing) Then
                    process.Dispose()
                End If
    
            End Try


    • Edited by Ran-jj Tuesday, October 8, 2019 5:34 PM
    Tuesday, October 8, 2019 5:34 PM
  • You need to set UseShellExecute to True, and be running as User Infra without passing credentials in startupinfo.  Otherwise an exception is thrown.


    • Edited by RLWA32 Tuesday, October 8, 2019 6:41 PM
    Tuesday, October 8, 2019 6:02 PM
  • So I have a C# service running as System I need to start a process with user infra as Admin, that's is the why I can run this program without pass user and password
    Tuesday, October 8, 2019 7:53 PM
  • Hi Ran-jj, 

    Thank you for posting here.

    According to your description, I make a test on my side.

    As RLWA32 suggested, set UseShellExecute to true can make the process run with admin powers.

    >> So I have a C# service running as System I need to start a process with user infra as Admin

    Could you describe more clearly about the reason why you cannot set UseShellExecute to true?

    We are waiting for your update.

    Best Regards,

    Xingyu Zhao


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, October 9, 2019 8:10 AM
    Moderator
  • So I have a C# service running as System I need to start a process with user infra as Admin, that's is the why I can run this program without pass user and password
    Do you intend to start an elevated process under the Infra account that shows a user interface?
    Wednesday, October 9, 2019 10:29 AM
  • Ok, I want to run a specific process under "user" account, that user has no admins powers but my account infra was admins powers.

    I already have a service running as System Account and I use "CreateProcessAsUser" to run a process as current user but the current user has no admins power, thats the why I need a helper to run a process as another admin user.

    When I set UseShellExecute to true I got a error (InvalidOperationException): 

     processStartInfo = New ProcessStartInfo With {
                .Verb = "runas",
                .LoadUserProfile = True,
                .FileName = "notepad.exe",
                .Arguments = "",
                .WindowStyle = ProcessWindowStyle.Normal,
                .UseShellExecute = True,
                .UserName = "Infra",
                .Domain = "INDRACPS040",
                .Password = TosecureString("Indra!@123"),
                .WorkingDirectory = "C:\WINDOWS\system32"
            }

    Wednesday, October 9, 2019 12:34 PM
  • You didn't answer my question -- do you intend to show a user interface?

    Services run in session 0 which is not interactive.  Any process started by a service that runs in session 0 will not display a user interface.

    Wednesday, October 9, 2019 1:16 PM
  • No I dont want to show a user interface.

    With "CreateProcessAsUser" I can start a process under user session.

    Wednesday, October 9, 2019 1:26 PM
  • No I dont want to show a user interface.

    With "CreateProcessAsUser" I can start a process under user session.

    Since are running as System and you have the credentials for Admin user Infra your service can use the Windows API -

    LogonUser to get a token, GetTokenInformation to get the linked token, then CreateProcessAsUser with the linked token to start an elevated process as Infra.


    • Edited by RLWA32 Wednesday, October 9, 2019 1:31 PM
    Wednesday, October 9, 2019 1:30 PM
  • Ok, I was reading about It.

    I'm going to write a sample and test

    Wednesday, October 9, 2019 2:19 PM
  • It's give me Erro code : 5. can you help me ?

    public static void CreateProcessAsUser(string userName, string pass, string domainName, string appPath, string cmdLine = null, string workDir = @"C:\Windows\System32", bool visible = false)
            {
                SafeTokenHandle safeTokenHandle;
    
                try
                {
    
                    const int LOGON32_PROVIDER_DEFAULT = 0;
                    //This parameter causes LogonUser to create a primary token.
                    const int LOGON32_LOGON_INTERACTIVE = 2;
    
                    // Call LogonUser to obtain a handle to an access token.
                    bool returnValue = LogonUser(userName, domainName, pass,
                        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                        out safeTokenHandle);
    
                    if (false == returnValue)
                    {
                        int ret = Marshal.GetLastWin32Error();
                        Console.WriteLine("LogonUser failed with error code : " + ret.ToString());
                        throw new System.ComponentModel.Win32Exception(ret);
                    }              
    
                    using (safeTokenHandle)
                    {
                        Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
                        Console.WriteLine("Value of Windows NT token: " + safeTokenHandle);
                        Console.WriteLine("Before impersonation: " + WindowsIdentity.GetCurrent().Name);
                        Console.WriteLine("Session Id: {0}", System.Diagnostics.Process.GetCurrentProcess().SessionId);
                        Console.WriteLine(WindowsIdentity.GetCurrent().Token);
    
                        using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(safeTokenHandle.DangerousGetHandle()))
                        {
                            // Check the identity.
                            Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
                            Console.WriteLine("Session Id: {0}", System.Diagnostics.Process.GetCurrentProcess().SessionId);
                            IntPtr tokenDuplicate = IntPtr.Zero;
                            IntPtr token = WindowsIdentity.GetCurrent().Token;
                            Console.WriteLine(token);
    
                            if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                            {
    
                                var hUserToken = tokenDuplicate;
                                var startInfo = new STARTUPINFO();
                                var procInfo = new PROCESS_INFORMATION();
                                var pEnv = IntPtr.Zero;
                                int iResultOfCreateProcessAsUser;
    
                                if (!CreateEnvironmentBlock(ref pEnv, hUserToken, true))
                                {
                                    throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
                                }
    
                                uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
                                startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
                                startInfo.lpDesktop = "winsta0\\default";
    
                                if (!CreateProcessAsUser(hUserToken,
                                    appPath, // Application Name
                                    cmdLine, // Command Line
                                    IntPtr.Zero,
                                    IntPtr.Zero,
                                    false,
                                    dwCreationFlags,
                                    pEnv,
                                    workDir, // Working directory
                                    ref startInfo,
                                    out procInfo))
                                {
                                    iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                                    throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -" + iResultOfCreateProcessAsUser);
                                }
    
                                iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                            
                                Console.WriteLine("done" );
                            }
                        }
    
                    }
                                   
                    } catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }

    Wednesday, October 9, 2019 7:59 PM
  • The code posted above appears as if it was intended to be executed from an interactive console application.

    You need to code and test for a Windows Service running as SYSTEM and provide for the fact that the elevated process you intend to start will not display a user interface.

    Further, the code does not call GetTokenInformation to obtain the linked token for a member of the Administrators group that will be used to start an elevated process.  There should not be a need to call DuplicateToken.

    For demo purposes I used the C# Windows service still available from A basic Windows service in C# (CSWindowsService)

    I added the following to the service so that it would use a thread to start the target process and then wait for it to complete so that it could unload the user profile and do other cleanup.  The service can be instructed to start the process from a command prompt by using the sc command -- "sc control CSWindowsService 142".  This allows you to attach a debugger to the service after it has started and set a breakpoint that will be hit when the worker thread is started.  While the sample code does do some checking on the results of Windows API function calls, it does not include all possible error checking and exception handling that might be appropriate.

            protected override void OnCustomCommand(int command)
            {
                if(command == 142)
                    ThreadPool.QueueUserWorkItem(new WaitCallback(StartProc));
            }
    
            private void StartProc(object state)
            {
                try
                {
                    IntPtr hToken;
    
                    if (Win32.LogonUser("Infra", "TEST", "test", Win32.LOGON32_LOGON_INTERACTIVE, Win32.LOGON32_PROVIDER_DEFAULT, out hToken))
                    {
                        int len = Marshal.SizeOf<Win32.TOKEN_LINKED_TOKEN>();
                        int retlen;
                        IntPtr tlt = Marshal.AllocHGlobal(len);
    
                        if (Win32.GetTokenInformation(hToken, Win32.TOKEN_INFORMATION_CLASS.TokenLinkedToken, tlt, len, out retlen))
                        {
                            Win32.TOKEN_LINKED_TOKEN linked = Marshal.PtrToStructure<Win32.TOKEN_LINKED_TOKEN>(tlt);
                            Win32.PROFILEINFO profinfo = new Win32.PROFILEINFO();
    
                            profinfo.dwSize = Marshal.SizeOf<Win32.PROFILEINFO>();
                            profinfo.lpUserName = "Infra";
                            if (Win32.LoadUserProfile(linked.LinkedToken, ref profinfo))
                            {
                                IntPtr pEnvironment;
                                if (Win32.CreateEnvironmentBlock(out pEnvironment, linked.LinkedToken, false))
                                {
                                    Win32.PROCESS_INFORMATION pi;
                                    Win32.STARTUPINFO si = new Win32.STARTUPINFO();
                                    Win32.SECURITY_ATTRIBUTES sa = new Win32.SECURITY_ATTRIBUTES();
    
                                    sa.nLength = Marshal.SizeOf<Win32.SECURITY_ATTRIBUTES>();
                                    si.cb = Marshal.SizeOf<Win32.STARTUPINFO>();
    
                                    bool bImpersonating = Win32.ImpersonateLoggedOnUser(linked.LinkedToken);
    
                                    if (Win32.CreateProcessAsUser(linked.LinkedToken,
                                        @"C:\Users\RLWA32\Documents\Visual Studio 2015\Projects\TokenLister\Debug\TokenLister.exe",
                                        string.Empty, ref sa, ref sa, false, Win32.CREATE_UNICODE_ENVIRONMENT,
                                        pEnvironment, @"C:\Temp", ref si, out pi))
                                    {
                                        uint exitCode;
    
                                        Win32.CloseHandle(pi.hThread);
                                        Win32.WaitForSingleObject(pi.hProcess, Win32.INFINITE);
                                        Win32.GetExitCodeProcess(pi.hProcess, out exitCode);
                                        Win32.CloseHandle(pi.hProcess);
    
                                        string strMsg = "Process TokenLister.exe terminated with return code " + exitCode.ToString();
                                        this.eventLog1.WriteEntry(strMsg, EventLogEntryType.Information);
                                    }
                                    else
                                    {
                                        int err = Marshal.GetLastWin32Error();
                                        string strError = "CreateProcessAsUser failed with error code " + err.ToString();
                                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                    }
    
                                    if (bImpersonating)
                                        Win32.RevertToSelf();
    
                                    Win32.DestroyEnvironmentBlock(pEnvironment);
                                }
                                else
                                {
                                    int err = Marshal.GetLastWin32Error();
                                    string strError = "CreateEnvironmentBlock failed with error code " + err.ToString();
                                    this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                                }
    
                                Win32.UnloadUserProfile(linked.LinkedToken, profinfo.hProfile);
                            }
                            else
                            {
                                int err = Marshal.GetLastWin32Error();
                                string strError = "LoadUserProfile failed with error code " + err.ToString();
                                this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                            }
    
                            Win32.CloseHandle(linked.LinkedToken);
                        }
                        else
                        {
                            int err = Marshal.GetLastWin32Error();
                            string strError = "GetTokenInformation failed with error code " + err.ToString();
                            this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                        }
    
                        Marshal.FreeHGlobal(tlt);
    
                        Win32.CloseHandle(hToken);
                    }
                    else
                    {
                        int err = Marshal.GetLastWin32Error();
                        string strError = "LogonUser failed with error code " + err.ToString();
                        this.eventLog1.WriteEntry(strError, EventLogEntryType.Error);
                    }
                }
                catch (Exception ex)
                {
                    string strExeption = "Caught exception : " + ex.Message;
                    this.eventLog1.WriteEntry(strExeption, EventLogEntryType.Error);
                }
            }
    
    

    The sample code above executes a process that writes information obtained from its token to a file.  When executed from the C# service, it produced the following output -

    Current Directory is C:\Temp
    Account Name is Infra
    High Integrity Process
    Session ID from Token is 0
    Token Has Elevated Privileges
    Token is an Elevated token
    Token is a Primary token
    

    This is the Win32 class that I used for the Windows API -

        public class Win32
        {
            public const int LOGON32_LOGON_INTERACTIVE = 2;
            public const int LOGON32_LOGON_NETWORK = 3;
            public const int LOGON32_LOGON_BATCH = 4;
            public const int LOGON32_LOGON_SERVICE = 5;
            public const int LOGON32_LOGON_UNLOCK = 7;
            public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
            public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
    
            public const int LOGON32_PROVIDER_DEFAULT = 0;
            public const int LOGON32_PROVIDER_WINNT35 = 1;
            public const int LOGON32_PROVIDER_WINNT40 = 2;
            public const int LOGON32_PROVIDER_WINNT50 = 3;
            public const int LOGON32_PROVIDER_VIRTUAL = 4;
    
            public const int DEBUG_PROCESS = 0x00000001;
            public const int DEBUG_ONLY_THIS_PROCESS = 0x00000002;
            public const int CREATE_SUSPENDED = 0x00000004;
            public const int DETACHED_PROCESS = 0x00000008;
    
            public const int CREATE_NEW_CONSOLE = 0x00000010;
            public const int NORMAL_PRIORITY_CLASS = 0x00000020;
            public const int IDLE_PRIORITY_CLASS = 0x00000040;
            public const int HIGH_PRIORITY_CLASS = 0x00000080;
    
            public const int REALTIME_PRIORITY_CLASS = 0x00000100;
            public const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
            public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
            public const int CREATE_SEPARATE_WOW_VDM = 0x00000800;
    
            public const int CREATE_SHARED_WOW_VDM = 0x00001000;
            public const int CREATE_FORCEDOS = 0x00002000;
            public const int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000;
            public const int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000;
    
            public const int INHERIT_PARENT_AFFINITY = 0x00010000;
            public const int INHERIT_CALLER_PRIORITY = 0x00020000;    // Deprecated
            public const int CREATE_PROTECTED_PROCESS = 0x00040000;
            public const int EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
    
            public const int PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000;
            public const int PROCESS_MODE_BACKGROUND_END = 0x00200000;
    
            public const int CREATE_BREAKAWAY_FROM_JOB = 0x01000000;
            public const int CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000;
            public const int CREATE_DEFAULT_ERROR_MODE = 0x04000000;
            public const int CREATE_NO_WINDOW = 0x08000000;
    
            public const uint INFINITE = 0xFFFFFFFF;
    
    
            [StructLayout(LayoutKind.Sequential)]
            public struct PROFILEINFO
            {
                public int dwSize;
                public int dwFlags;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpUserName;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpProfilePath;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpDefaultPath;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpServerName;
                [MarshalAs(UnmanagedType.LPWStr)]
                public String lpPolicyPath;
                public IntPtr hProfile;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct TOKEN_LINKED_TOKEN
            {
                public IntPtr LinkedToken;
            }
    
            public enum TOKEN_INFORMATION_CLASS
            {
                TokenUser = 1,
                TokenGroups,
                TokenPrivileges,
                TokenOwner,
                TokenPrimaryGroup,
                TokenDefaultDacl,
                TokenSource,
                TokenType,
                TokenImpersonationLevel,
                TokenStatistics,
                TokenRestrictedSids,
                TokenSessionId,
                TokenGroupsAndPrivileges,
                TokenSessionReference,
                TokenSandBoxInert,
                TokenAuditPolicy,
                TokenOrigin,
                TokenElevationType,
                TokenLinkedToken,
                TokenElevation,
                TokenHasRestrictions,
                TokenAccessInformation,
                TokenVirtualizationAllowed,
                TokenVirtualizationEnabled,
                TokenIntegrityLevel,
                TokenUIAccess,
                TokenMandatoryPolicy,
                TokenLogonSid,
                TokenIsAppContainer,
                TokenCapabilities,
                TokenAppContainerSid,
                TokenAppContainerNumber,
                TokenUserClaimAttributes,
                TokenDeviceClaimAttributes,
                TokenRestrictedUserClaimAttributes,
                TokenRestrictedDeviceClaimAttributes,
                TokenDeviceGroups,
                TokenRestrictedDeviceGroups,
                TokenSecurityAttributes,
                TokenIsRestricted,
                TokenProcessTrustLevel,
                TokenPrivateNameSpace,
                TokenSingletonAttributes,
                MaxTokenInfoClass  // MaxTokenInfoClass should always be the last enum
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SECURITY_ATTRIBUTES
            {
                public int nLength;
                public IntPtr lpSecurityDescriptor;
                public int bInheritHandle;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            public struct STARTUPINFO
            {
                public int cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public uint dwX;
                public uint dwY;
                public uint dwXSize;
                public uint dwYSize;
                public uint dwXCountChars;
                public uint dwYCountChars;
                public uint dwFillAttribute;
                public uint dwFlags;
                public ushort wShowWindow;
                public ushort cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public uint dwProcessId;
                public uint dwThreadId;
            }
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool LogonUser(string user, string domain, string password, uint type, uint provider, out IntPtr hToken);
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CloseHandle(IntPtr handle);
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            public static extern uint WaitForSingleObject(IntPtr handle, uint dwMilliseconds);
    
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetExitCodeProcess(IntPtr handle, out uint exitCode);
    
            [DllImport("userenv.dll",  CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);
    
            [DllImport("userenv.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile);
    
            [DllImport("userenv.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
    
            [DllImport("userenv.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
                                                          IntPtr TokenInformation, int TokenInformationLength, out int ReturnLength);
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool ImpersonateLoggedOnUser(IntPtr TokenHandle);
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool RevertToSelf();
    
            [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CreateProcessAsUser(
                IntPtr hToken,
                string lpApplicationName,
                string lpCommandLine,
                ref SECURITY_ATTRIBUTES lpProcessAttributes,
                ref SECURITY_ATTRIBUTES lpThreadAttributes,
                bool bInheritHandles,
                uint dwCreationFlags,
                IntPtr lpEnvironment,
                string lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);
    
        }
    

    • Proposed as answer by RLWA32 Friday, October 11, 2019 9:32 AM
    • Marked as answer by Ran-jj Friday, October 11, 2019 12:58 PM
    Thursday, October 10, 2019 10:55 AM
  • I'm using the same example code and I got error.

    Thursday, October 10, 2019 12:37 PM
  • The demo service containing the sample code was built with VS2015 and .Net Framework version 4.5.2

    Did you add the required using statements to the demo service code?  For example, System.Runtime.InteropServices?

    • Edited by RLWA32 Thursday, October 10, 2019 1:01 PM
    Thursday, October 10, 2019 12:40 PM
  • Aeeeee. It works.

    But is in the sistem context, why ?


    Thursday, October 10, 2019 3:11 PM
  • Aeeeee. It works.

    But is in the sistem context, why ?


    Elevated processes have an Integrity level of High. A typical process that runs as a standard user has an integrity level of Medium.  It is not running as SYSTEM, but as user infra.

    I don't understand the language in the images that you post.  Kindly provide English translation going forward.


    • Edited by RLWA32 Thursday, October 10, 2019 3:35 PM
    Thursday, October 10, 2019 3:31 PM
  • Since windows services run in non-interactive session 0 a process started by a service using CreateProcessAsUser using the token obtained by calling LogonUser will also run in session 0.

    You can change the session number in the token by using SetTokenInformation and token information class TokenSessionId before you pass it to CreateProcessAsUser.

    Since you indicated that your process did not need to present a user interface it seemed that starting the process in session 0 would be sufficient.

    If your issues have been solved, kindly mark my response as the answer to close this thread.

    Friday, October 11, 2019 10:57 AM
  • the problem is I have a capture program and there is no UI, but if the program start on ID 0 I can't capture the current user screen.
    Friday, October 11, 2019 12:11 PM
  • Can you give me a exampe of SetTokenInformation ?
    Friday, October 11, 2019 12:15 PM
  • Can you give me a exampe of SetTokenInformation ?

    You have made this thread a moving target.

    First, there was no mention of a windows service.

    After you indicated that you wanted to start a non-interactive process as Admin from a Windows service I provided code that solved the issue.

    Now you have changed the question again by adding that you want to do this for a process that does screen capture in a user's interactive session.

    So, I suggest you close this thread and ask a new question that provides all the relevant details.

    Friday, October 11, 2019 12:43 PM
  • ok ok
    Friday, October 11, 2019 12:57 PM