C# 管理服务:将用户登录到桌面,生成一个可以和桌面交互的进程

C# 管理服务:将用户登录到桌面,生成一个可以和桌面交互的进程,c#,windows,service,impersonation,C#,Windows,Service,Impersonation,我很难让一个非常具体的用例工作。该应用程序有两个组件:一个Windows服务,需要在桌面之外的特权上下文中运行(即在用户登录或未登录时接受连接),另一个客户端Winforms应用程序。该服务接受websocket连接,如果连接请求成功,它应该以交互方式登录用户(进入桌面),并生成一个进程,作为具有桌面访问权限的用户。我使用了以下链接,虽然它们能够模拟用户,但实际上不会将用户登录到桌面,即,如果我使用VNC观看系统,或者如果我在本地系统上测试系统,则用户不会登录。然而,这个过程确实是以用户的身份产

我很难让一个非常具体的用例工作。该应用程序有两个组件:一个Windows服务,需要在桌面之外的特权上下文中运行(即在用户登录或未登录时接受连接),另一个客户端Winforms应用程序。该服务接受websocket连接,如果连接请求成功,它应该以交互方式登录用户(进入桌面),并生成一个进程,作为具有桌面访问权限的用户。我使用了以下链接,虽然它们能够模拟用户,但实际上不会将用户登录到桌面,即,如果我使用VNC观看系统,或者如果我在本地系统上测试系统,则用户不会登录。然而,这个过程确实是以用户的身份产生的,但显然不是通过桌面访问

是否有人拥有将用户登录到桌面的代码示例

我尝试过的链接和代码:

公开的

目前的代码是:

using Cassia;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.DirectoryServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using System.ServiceProcess;

namespace program
{
    public partial class service
    {
        #region Interop

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public UInt32 LowPart;
            public Int32 HighPart;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID_AND_ATTRIBUTES
        {
            public LUID Luid;
            public UInt32 Attributes;
        }

        public struct TOKEN_PRIVILEGES
        {
            public UInt32 PrivilegeCount;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
            public LUID_AND_ATTRIBUTES[] Privileges;
        }

        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,
            MaxTokenInfoClass
        }

        [Flags]
        enum CreationFlags : uint
        {
            CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
            CREATE_DEFAULT_ERROR_MODE = 0x04000000,
            CREATE_NEW_CONSOLE = 0x00000010,
            CREATE_NEW_PROCESS_GROUP = 0x00000200,
            CREATE_NO_WINDOW = 0x08000000,
            CREATE_PROTECTED_PROCESS = 0x00040000,
            CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
            CREATE_SEPARATE_WOW_VDM = 0x00001000,
            CREATE_SUSPENDED = 0x00000004,
            CREATE_UNICODE_ENVIRONMENT = 0x00000400,
            DEBUG_ONLY_THIS_PROCESS = 0x00000002,
            DEBUG_PROCESS = 0x00000001,
            DETACHED_PROCESS = 0x00000008,
            EXTENDED_STARTUPINFO_PRESENT = 0x00080000
        }

        public enum TOKEN_TYPE
        {
            TokenPrimary = 1,
            TokenImpersonation
        }

        public enum SECURITY_IMPERSONATION_LEVEL
        {
            SecurityAnonymous,
            SecurityIdentification,
            SecurityImpersonation,
            SecurityDelegation
        }

        [Flags]
        enum LogonFlags
        {
            LOGON_NETCREDENTIALS_ONLY = 2,
            LOGON_WITH_PROFILE = 1
        }

        enum LOGON_TYPE
        {
            LOGON32_LOGON_INTERACTIVE = 2,
            LOGON32_LOGON_NETWORK,
            LOGON32_LOGON_BATCH,
            LOGON32_LOGON_SERVICE,
            LOGON32_LOGON_UNLOCK = 7,
            LOGON32_LOGON_NETWORK_CLEARTEXT,
            LOGON32_LOGON_NEW_CREDENTIALS
        }

        enum LOGON_PROVIDER
        {
            LOGON32_PROVIDER_DEFAULT,
            LOGON32_PROVIDER_WINNT35,
            LOGON32_PROVIDER_WINNT40,
            LOGON32_PROVIDER_WINNT50
        }

        struct SECURITY_ATTRIBUTES
        {
            public uint Length;
            public IntPtr SecurityDescriptor;
            public bool InheritHandle;
        }

        [Flags]
        enum SECURITY_INFORMATION : uint
        {
            OWNER_SECURITY_INFORMATION = 0x00000001,
            GROUP_SECURITY_INFORMATION = 0x00000002,
            DACL_SECURITY_INFORMATION = 0x00000004,
            SACL_SECURITY_INFORMATION = 0x00000008,
            UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000,
            UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
            PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000,
            PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
        }

        [StructLayoutAttribute(LayoutKind.Sequential)]
        struct SECURITY_DESCRIPTOR
        {
            public byte revision;
            public byte size;
            public short control; // public SECURITY_DESCRIPTOR_CONTROL control;
            public IntPtr owner;
            public IntPtr group;
            public IntPtr sacl;
            public IntPtr dacl;
        }

        struct STARTUPINFO
        {
            public uint cb;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string Reserved;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string Desktop;
            [MarshalAs(UnmanagedType.LPTStr)]
            public string Title;
            public uint X;
            public uint Y;
            public uint XSize;
            public uint YSize;
            public uint XCountChars;
            public uint YCountChars;
            public uint FillAttribute;
            public uint Flags;
            public ushort ShowWindow;
            public ushort Reserverd2;
            public byte bReserverd2;
            public IntPtr StdInput;
            public IntPtr StdOutput;
            public IntPtr StdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct PROCESS_INFORMATION
        {
            public IntPtr Process;
            public IntPtr Thread;
            public uint ProcessId;
            public uint ThreadId;
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool InitializeSecurityDescriptor(IntPtr pSecurityDescriptor, uint dwRevision);
        const uint SECURITY_DESCRIPTOR_REVISION = 1;

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool daclPresent, IntPtr dacl, bool daclDefaulted);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        extern static bool DuplicateTokenEx(
            IntPtr hExistingToken,
            uint dwDesiredAccess,
            ref SECURITY_ATTRIBUTES lpTokenAttributes,
            SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
            TOKEN_TYPE TokenType,
            out IntPtr phNewToken);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(
            string lpszUsername,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            out IntPtr phToken
            );

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool GetTokenInformation(
            IntPtr TokenHandle,
            TOKEN_INFORMATION_CLASS TokenInformationClass,
            IntPtr TokenInformation,
            int TokenInformationLength,
            out int ReturnLength
            );

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool CreateProcessAsUser(
            IntPtr Token,
            [MarshalAs(UnmanagedType.LPTStr)] string ApplicationName,
            [MarshalAs(UnmanagedType.LPTStr)] string CommandLine,
            ref SECURITY_ATTRIBUTES ProcessAttributes,
            ref SECURITY_ATTRIBUTES ThreadAttributes,
            bool InheritHandles,
            uint CreationFlags,
            IntPtr Environment,
            [MarshalAs(UnmanagedType.LPTStr)] string CurrentDirectory,
            ref STARTUPINFO StartupInfo,
            out PROCESS_INFORMATION ProcessInformation);

        [DllImport("Kernel32.dll")]
        extern static int CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

        [DllImport("advapi32.dll", SetLastError = true)]
        internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct TokPriv1Luid
        {
            public int Count;
            public long Luid;
            public int Attr;
        }

        internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
        internal const int TOKEN_QUERY = 0x00000008;
        internal const int TOKEN_DUPLICATE = 0x0002;
        internal const int TOKEN_ASSIGN_PRIMARY = 0x0001;

        #endregion

        public static bool LoginUser(string domain, string username, string password, string program, string workingDir)
        {
            IntPtr token = IntPtr.Zero;
            IntPtr primaryToken = IntPtr.Zero;

            try
            {
                bool result = LogonUser(username, domain, password, (int)LOGON_TYPE.LOGON32_LOGON_NETWORK, (int)LOGON_PROVIDER.LOGON32_PROVIDER_DEFAULT, out token);
                if (!result)
                {
                    int winError = Marshal.GetLastWin32Error();
                    Console.WriteLine("LoginUser unable to login user " + username + ", error: " + winError);
                    return false;
                }

                SECURITY_ATTRIBUTES processAttributes = new SECURITY_ATTRIBUTES();
                SECURITY_DESCRIPTOR sd = new SECURITY_DESCRIPTOR();
                IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(sd));
                Marshal.StructureToPtr(sd, ptr, false);
                InitializeSecurityDescriptor(ptr, SECURITY_DESCRIPTOR_REVISION);
                sd = (SECURITY_DESCRIPTOR)Marshal.PtrToStructure(ptr, typeof(SECURITY_DESCRIPTOR));

                result = SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false);
                if (!result)
                {
                    int winError = Marshal.GetLastWin32Error();
                }

                primaryToken = new IntPtr();
                result = DuplicateTokenEx(token, 0, ref processAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
                if (!result)
                {
                    int winError = Marshal.GetLastWin32Error();
                }

                processAttributes.SecurityDescriptor = ptr;
                processAttributes.Length = (uint)Marshal.SizeOf(sd);
                processAttributes.InheritHandle = true;

                SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
                threadAttributes.SecurityDescriptor = IntPtr.Zero;
                threadAttributes.Length = 0;
                threadAttributes.InheritHandle = false;

                bool inheritHandles = true;
                IntPtr environment = IntPtr.Zero;

                STARTUPINFO startupInfo = new STARTUPINFO();
                startupInfo.Desktop = "";

                PROCESS_INFORMATION processInformation;

                result = CreateProcessAsUser(
                    primaryToken,
                    program,
                    program, 
                    ref processAttributes, 
                    ref threadAttributes, 
                    inheritHandles, 
                    16, 
                    environment, 
                    workingDir,
                    ref startupInfo, 
                    out processInformation);

                if (!result)
                {
                    int winError = Marshal.GetLastWin32Error();
                    Console.WriteLine("LoginUser unable to create process as user " + username + ", error: " + winError);
                    return false;
                }

                return true;
            } 
            catch (Exception e) 
            {
                Console.WriteLine("LoginUser exception encountered: " + e.Message());
                return false;
            } 
            finally
            {
                if (token != IntPtr.Zero)
                {
                    int x = CloseHandle(token);
                    if (x == 0)
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    x = CloseHandle(primaryToken);
                    if (x == 0)
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
        }

        public static SecureString securePassword(string password)
        {
            if (string_null(password)) return null;
            SecureString secure = new SecureString();
            foreach (char c in password)
            {
                secure.AppendChar(c);
            }
            return secure;
        }
    }
}
我的目标是能够简单地称之为:

if (!LoginUser("machinename", "username", "password", "c:\\path\\to\\program.exe", "c:\\path\\to"))
{
  // error
}
else
{
  // success, user is logged into desktop and app is launch
  // as user with desktop access
}

我以前也有过同样的场景,事情变得复杂了,所以我只是将PSEXEC过程结合使用

只需使用PSEXEC,就像他们的示例中所示,您所要做的就是这样

通过代码或手动(即program.exe)将可执行文件复制或安装到远程系统,并在DannyGlover帐户下以交互方式执行:

psexec \\workstation64 -c program.exe -u YourUser -p YourPa55w0rd
现在您知道了参数,然后可以使用进程。启动运行它。 所以它看起来像这样

using System.Diagnostics;
...
Process process = new Process();
process.StartInfo.FileName = "program.exe";
process.StartInfo.Arguments = "\\workstation64 -c program.exe -u YourUser -p YourPa55w0rd";
process.Start();
process.WaitForExit();
顺便说一下,您可以在这里了解更多信息并下载PSEXEC

我在Elance.com上找到了您的问题,并找到了此链接

我的一个项目也有同样的问题。这需要windows服务启动POS终端communicator exe,并且应该具有具有管理员访问权限的UI。我尝试了相同的winlogon.exe模拟以避免UAC,但没有帮助

对于我的问题,我使用了计划任务,并使用c#创建了我的任务。 你可以在这里找到一个很好的图书馆。 现在,在一个需要的调用中,您可以动态运行任务,并且您可以完全控制该任务


您可以动态创建自己的任务/编辑/删除,也可以通过不避开UAC来运行应用程序。

您正在寻求创建新的交互式会话。不幸的是,这是不可能的。据我所知,您希望启动一个进程,然后使用VNC远程控制机器。也许你只需要使用远程桌面?

嗨,Raymund,这会不会真的将用户登录到桌面并启动应用程序?它不会以物理方式运行,但会在你所指的桌面/工作站上运行应用程序,即你指定的用户。我在我们的场景中特别使用了这一点,在200多家商店中有服务器,我们需要分发一个可执行文件并以某个用户的身份运行。谢谢,但问题是我需要代表用户运行的应用程序使用的服务要求该帐户具有桌面访问权限,因此,这将不起作用。这将代表运行并具有桌面访问权限。你试过了吗?与编写一大块代码相比,您只需要这5行代码和名称空间。因为我们有一个旧的应用程序,它没有API,我们需要以用户身份运行进程。嗨,Raymund,是的,我尝试过这个方法(必须将process.StartInfo.Filename更改为'psexec.exe',\\workstation64更改为\\,并相应地将program.exe)。它没有在用户的桌面上生成应用程序。它是在后台产生的。嗨,Codeguard,这在技术上是可能的,因为许多信息亭都建立了自己的身份验证提供商来做到这一点,我希望在我自己的应用程序中做到这一点。由于我不能在这里详细介绍的原因,它必须以编程方式完成,而不允许用户直接查看登录屏幕或与之交互。