zoukankan      html  css  js  c++  java
  • C#穿透session隔离———Windows服务启动UI交互程序 be

    在Windows服务里面启动其他具有界面的应用程序,需要穿透session隔离,尝试了很多种方法,都可行,现在一一列举下来,并写下几个需要注意的地方。

    需要注意的地方

    • 首先要将服务的Account属性设置为LocalSystem,安装服务后的登录身份则为本地系统账户

           

    • 再一个需要注意的是不要把Windows服务的程序放在C:\Users\Administrator\目录下运行,不然启动服务的时候会遇到权限问题,如下图

     

    实现代码如下

    • 第一种方法

    调用方法

    WinAPI_Interop.CreateProcess(path);//string path=@"C:\Users\Administrator\Text.exe";

    代码类

     public class WinAPI_Interop
        {
            public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
            /// <summary>
            /// 服务程序执行消息提示,前台MessageBox.Show
            /// </summary>
            /// <param name="message">消息内容</param>
            /// <param name="title">标题</param>
            public static void ShowServiceMessage(string message, string title)
            {
                int resp = 0;
                WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), title, title.Length, message, message.Length, 0, 0, out resp, false);
            }
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern int WTSGetActiveConsoleSessionId();
    
            [DllImport("wtsapi32.dll", SetLastError = true)]
            public static extern bool WTSSendMessage(IntPtr hServer, int SessionId, String pTitle, int TitleLength, String pMessage, int MessageLength, int Style, int Timeout, out int pResponse, bool bWait);
            #region P/Invoke WTS APIs
            private enum WTS_CONNECTSTATE_CLASS
            {
                WTSActive,
                WTSConnected,
                WTSConnectQuery,
                WTSShadow,
                WTSDisconnected,
                WTSIdle,
                WTSListen,
                WTSReset,
                WTSDown,
                WTSInit
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            private struct WTS_SESSION_INFO
            {
                public UInt32 SessionID;
                public string pWinStationName;
                public WTS_CONNECTSTATE_CLASS State;
            }
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool WTSEnumerateSessions(
                IntPtr hServer,
                [MarshalAs(UnmanagedType.U4)] UInt32 Reserved,
                [MarshalAs(UnmanagedType.U4)] UInt32 Version,
                ref IntPtr ppSessionInfo,
                [MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount
                );
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern void WTSFreeMemory(IntPtr pMemory);
    
            [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
            #endregion
    
            #region P/Invoke CreateProcessAsUser
            /// <summary> 
            /// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser. 
            /// </summary> 
            ///  
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            struct STARTUPINFO
            {
                public Int32 cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public Int32 dwX;
                public Int32 dwY;
                public Int32 dwXSize;
                public Int32 dwYSize;
                public Int32 dwXCountChars;
                public Int32 dwYCountChars;
                public Int32 dwFillAttribute;
                public Int32 dwFlags;
                public Int16 wShowWindow;
                public Int16 cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public int dwProcessId;
                public int dwThreadId;
            }
    
            /// <summary>
            /// 以当前登录的windows用户(角色权限)运行指定程序进程
            /// </summary>
            /// <param name="hToken"></param>
            /// <param name="lpApplicationName">指定程序(全路径)</param>
            /// <param name="lpCommandLine">参数</param>
            /// <param name="lpProcessAttributes">进程属性</param>
            /// <param name="lpThreadAttributes">线程属性</param>
            /// <param name="bInheritHandles"></param>
            /// <param name="dwCreationFlags"></param>
            /// <param name="lpEnvironment"></param>
            /// <param name="lpCurrentDirectory"></param>
            /// <param name="lpStartupInfo">程序启动属性</param>
            /// <param name="lpProcessInformation">最后返回的进程信息</param>
            /// <returns>是否调用成功</returns>
            [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,
                                                          bool bInheritHandles, uint dwCreationFlags, string lpEnvironment, string lpCurrentDirectory,
                                                          ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
    
            [DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
            static extern bool CloseHandle(IntPtr hHandle);
            #endregion
    
            /// <summary>
            /// 以当前登录系统的用户角色权限启动指定的进程
            /// </summary>
            /// <param name="ChildProcName">指定的进程(全路径)</param>
            public static void CreateProcess(string ChildProcName)
            {
                IntPtr ppSessionInfo = IntPtr.Zero;
                UInt32 SessionCount = 0;
                if (WTSEnumerateSessions(
                                        (IntPtr)WTS_CURRENT_SERVER_HANDLE,  // Current RD Session Host Server handle would be zero. 
                                        0,  // This reserved parameter must be zero. 
                                        1,  // The version of the enumeration request must be 1. 
                                        ref ppSessionInfo, // This would point to an array of session info. 
                                        ref SessionCount  // This would indicate the length of the above array.
                                        ))
                {
                    for (int nCount = 0; nCount < SessionCount; nCount++)
                    {
                        WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)), typeof(WTS_SESSION_INFO));
                        if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
                        {
                            IntPtr hToken = IntPtr.Zero;
                            if(WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
                            {
                                PROCESS_INFORMATION tProcessInfo;
                                STARTUPINFO tStartUpInfo = new STARTUPINFO();
                                tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
                                bool ChildProcStarted = CreateProcessAsUser(
                                                                            hToken,             // Token of the logged-on user. 
                                                                            ChildProcName,      // Name of the process to be started. 
                                                                            null,               // Any command line arguments to be passed. 
                                                                            IntPtr.Zero,        // Default Process' attributes. 
                                                                            IntPtr.Zero,        // Default Thread's attributes. 
                                                                            false,              // Does NOT inherit parent's handles. 
                                                                            0,                  // No any specific creation flag. 
                                                                            null,               // Default environment path. 
                                                                            null,               // Default current directory. 
                                                                            ref tStartUpInfo,   // Process Startup Info.  
                                                                            out tProcessInfo    // Process information to be returned. 
                                                         );
                                if (ChildProcStarted)
                                {
                                    CloseHandle(tProcessInfo.hThread);
                                    CloseHandle(tProcessInfo.hProcess);
                                }
                                else
                                {
                                    ShowServiceMessage("CreateProcessAsUser失败", "CreateProcess");
                                }
                                CloseHandle(hToken);
                                break;
                            }
                        }
                    }
                    WTSFreeMemory(ppSessionInfo);
                }
            }
        }
    View Code
    • 第二种方法

    调用方法

     Interops.CreateProcess(path, @"C:\Windows\System32\");//string path=@"C:\Users\Administrator\Text.exe";

    代码类

       public class Interops
        {
            public static void CreateProcess(string app, string path)
            {
                bool result;
                IntPtr hToken = WindowsIdentity.GetCurrent().Token;
                IntPtr hDupedToken = IntPtr.Zero;
    
                PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
                SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
                sa.Length = Marshal.SizeOf(sa);
    
                STARTUPINFO si = new STARTUPINFO();
                si.cb = Marshal.SizeOf(si);
    
                int dwSessionID = 0;// WTSGetActiveConsoleSessionId();
                result = WTSQueryUserToken(dwSessionID, out hToken);
    
                if (!result)
                {
                    ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
                }
    
                result = DuplicateTokenEx(
                hToken,
                GENERIC_ALL_ACCESS,
                ref sa,
                (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                (int)TOKEN_TYPE.TokenPrimary,
                ref hDupedToken
                );
    
                if (!result)
                {
                    ShowMessageBox("DuplicateTokenEx failed", "AlertService Message");
                }
    
                IntPtr lpEnvironment = IntPtr.Zero;
                result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
    
                if (!result)
                {
                    ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
                }
    
                result = CreateProcessAsUser(
                hDupedToken,
                app,
                String.Empty,
                ref sa, ref sa,
                false, 0, IntPtr.Zero,
                null, ref si, ref pi);
    
                if (!result)
                {
                    int error = Marshal.GetLastWin32Error();
                    string message = String.Format("CreateProcessAsUser Error: {0}", error);
                    ShowMessageBox(message, "AlertService Message");
                }
    
                if (pi.hProcess != IntPtr.Zero)
                    CloseHandle(pi.hProcess);
                if (pi.hThread != IntPtr.Zero)
                    CloseHandle(pi.hThread);
                if (hDupedToken != IntPtr.Zero)
                    CloseHandle(hDupedToken);
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct STARTUPINFO
            {
                public Int32 cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public Int32 dwX;
                public Int32 dwY;
                public Int32 dwXSize;
                public Int32 dwXCountChars;
                public Int32 dwYCountChars;
                public Int32 dwFillAttribute;
                public Int32 dwFlags;
                public Int16 wShowWindow;
                public Int16 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 Int32 dwProcessID;
                public Int32 dwThreadID;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SECURITY_ATTRIBUTES
            {
                public Int32 Length;
                public IntPtr lpSecurityDescriptor;
                public bool bInheritHandle;
            }
    
            public enum SECURITY_IMPERSONATION_LEVEL
            {
                SecurityAnonymous,
                SecurityIdentification,
                SecurityImpersonation,
                SecurityDelegation
            }
    
            public enum TOKEN_TYPE
            {
                TokenPrimary = 1,
                TokenImpersonation
            }
    
            public const int GENERIC_ALL_ACCESS = 0x10000000;
    
            [DllImport("kernel32.dll", SetLastError = true,
            CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            public static extern bool CloseHandle(IntPtr handle);
    
            [DllImport("advapi32.dll", SetLastError = true,
            CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
            public static extern bool CreateProcessAsUser(
            IntPtr hToken,
            string lpApplicationName,
            string lpCommandLine,
            ref SECURITY_ATTRIBUTES lpProcessAttributes,
            ref SECURITY_ATTRIBUTES lpThreadAttributes,
            bool bInheritHandle,
            Int32 dwCreationFlags,
            IntPtr lpEnvrionment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            ref PROCESS_INFORMATION lpProcessInformation);
    
            [DllImport("advapi32.dll", SetLastError = true)]
            public static extern bool DuplicateTokenEx(
            IntPtr hExistingToken,
            Int32 dwDesiredAccess,
            ref SECURITY_ATTRIBUTES lpThreadAttributes,
            Int32 ImpersonationLevel,
            Int32 dwTokenType,
            ref IntPtr phNewToken);
    
            [DllImport("wtsapi32.dll", SetLastError = true)]
            public static extern bool WTSQueryUserToken(
            Int32 sessionId,
            out IntPtr Token);
    
            [DllImport("userenv.dll", SetLastError = true)]
            static extern bool CreateEnvironmentBlock(
            out IntPtr lpEnvironment,
            IntPtr hToken,
            bool bInherit);
    
            public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
            public static void ShowMessageBox(string message, string title)
            {
                int resp = 0;
                WTSSendMessage(
                WTS_CURRENT_SERVER_HANDLE,
                WTSGetActiveConsoleSessionId(),
                title, title.Length,
                message, message.Length,
                0, 0, out resp, false);
            }
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern int WTSGetActiveConsoleSessionId();
    
            [DllImport("wtsapi32.dll", SetLastError = true)]
            public static extern bool WTSSendMessage(
            IntPtr hServer,
            int SessionId,
            String pTitle,
            int TitleLength,
            String pMessage,
            int MessageLength,
            int Style,
            int Timeout,
            out int pResponse,
            bool bWait);
        }
    View Code
    • 第三种方法(可以远程)

    调用方法

    SessionUtility.CreateProcess(@"C:\Windows\System32\", path, 1);//string path=@"C:\Users\Administrator\Test.exe";

    代码类

     /// <summary>
        /// 解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离
        /// 用于windows服务 启动外部程序 或者截取图片等
        /// 默认windows服务的权限是在session0中
        /// </summary>
        public class SessionUtility
        {
            #region 如果服务只是简单的向桌面用户Session 发送消息窗口,则可以使用WTSSendMessage 函数实现
    
            public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
    
            public static void ShowMessageBox(string message, string title)
            {
                int resp = 0;
                WTSSendMessage(
                    WTS_CURRENT_SERVER_HANDLE,
                    WTSGetActiveConsoleSessionId(),
                    title, title.Length,
                    message, message.Length,
                    0, 0, out resp, false);
            }
    
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern int WTSGetActiveConsoleSessionId();
    
            [DllImport("wtsapi32.dll", SetLastError = true)]
            public static extern bool WTSSendMessage(
                IntPtr hServer,
                int SessionId,
                String pTitle,
                int TitleLength,
                String pMessage,
                int MessageLength,
                int Style,
                int Timeout,
                out int pResponse,
                bool bWait);
    
            //在ShowMessageBox 函数中调用了WTSSendMessage 来发送信息窗口,这样我们就可以在Service 的OnStart 函数中使用,打开Service1.cs 加入下面代码:
            //protected override void OnStart(string[] args)
            //{
            //    Interop.ShowMessageBox("This a message from AlertService.",
            //                           "AlertService Message");
            //}
    
            #endregion
    
            /*
             * 如果想通过服务向桌面用户Session 创建一个复杂UI 程序界面,
             * 则需要使用CreateProcessAsUser 函数为用户创建一个新进程用来运行相应的程序。
             */
    
            #region 复杂进程
    
            public static void CreateProcess(string app, string para, int sessionID)
            {
                if (!string.IsNullOrEmpty(para))
                {
                    para = app + @"\" + para;
                    app = null;
                }
                bool result;
                IntPtr hToken = WindowsIdentity.GetCurrent().Token;
                IntPtr hDupedToken = IntPtr.Zero;
    
                var pi = new PROCESS_INFORMATION();
                var sa = new SECURITY_ATTRIBUTES();
                sa.Length = Marshal.SizeOf(sa);
    
                var si = new STARTUPINFO();
                si.cb = Marshal.SizeOf(si);
    
                int dwSessionID = sessionID;
                if (sessionID < 0)
                    dwSessionID = WTSGetActiveConsoleSessionId();
                result = WTSQueryUserToken(dwSessionID, out hToken);
    
                if (!result)
                {
                    ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
                }
    
                result = DuplicateTokenEx(
                    hToken,
                    GENERIC_ALL_ACCESS,
                    ref sa,
                    (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                    (int)TOKEN_TYPE.TokenPrimary,
                    ref hDupedToken
                    );
    
                if (!result)
                {
                    ShowMessageBox("DuplicateTokenEx failed", "AlertService Message");
                }
    
                IntPtr lpEnvironment = IntPtr.Zero;
                result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
    
                if (!result)
                {
                    ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
                }
    
                result = CreateProcessAsUser(
                    hDupedToken,
                    app,
                    para,
                    ref sa, ref sa,
                    false, 0, IntPtr.Zero,
                    null, ref si, ref pi);
    
                if (!result)
                {
                    int error = Marshal.GetLastWin32Error();
                    string message = String.Format("CreateProcessAsUser Error: {0}", error);
                    ShowMessageBox(message, "AlertService Message");
                }
    
                if (pi.hProcess != IntPtr.Zero)
                    CloseHandle(pi.hProcess);
                if (pi.hThread != IntPtr.Zero)
                    CloseHandle(pi.hThread);
                if (hDupedToken != IntPtr.Zero)
                    CloseHandle(hDupedToken);
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct STARTUPINFO
            {
                public Int32 cb;
                public string lpReserved;
                public string lpDesktop;
                public string lpTitle;
                public Int32 dwX;
                public Int32 dwY;
                public Int32 dwXSize;
                public Int32 dwXCountChars;
                public Int32 dwYCountChars;
                public Int32 dwFillAttribute;
                public Int32 dwFlags;
                public Int16 wShowWindow;
                public Int16 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 Int32 dwProcessID;
                public Int32 dwThreadID;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SECURITY_ATTRIBUTES
            {
                public Int32 Length;
                public IntPtr lpSecurityDescriptor;
                public bool bInheritHandle;
            }
    
            public enum SECURITY_IMPERSONATION_LEVEL
            {
                SecurityAnonymous,
                SecurityIdentification,
                SecurityImpersonation,
                SecurityDelegation
            }
    
            public enum TOKEN_TYPE
            {
                TokenPrimary = 1,
                TokenImpersonation
            }
    
            public const int GENERIC_ALL_ACCESS = 0x10000000;
    
            [DllImport("kernel32.dll", SetLastError = true,
                CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            public static extern bool CloseHandle(IntPtr handle);
    
            [DllImport("advapi32.dll", SetLastError = true,
                CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
            public static extern bool CreateProcessAsUser(
                IntPtr hToken,
                string lpApplicationName,
                string lpCommandLine,
                ref SECURITY_ATTRIBUTES lpProcessAttributes,
                ref SECURITY_ATTRIBUTES lpThreadAttributes,
                bool bInheritHandle,
                Int32 dwCreationFlags,
                IntPtr lpEnvrionment,
                string lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                ref PROCESS_INFORMATION lpProcessInformation);
    
            [DllImport("advapi32.dll", SetLastError = true)]
            public static extern bool DuplicateTokenEx(
                IntPtr hExistingToken,
                Int32 dwDesiredAccess,
                ref SECURITY_ATTRIBUTES lpThreadAttributes,
                Int32 ImpersonationLevel,
                Int32 dwTokenType,
                ref IntPtr phNewToken);
    
            [DllImport("wtsapi32.dll", SetLastError = true)]
            public static extern bool WTSQueryUserToken(
                Int32 sessionId,
                out IntPtr Token);
    
            [DllImport("userenv.dll", SetLastError = true)]
            private static extern bool CreateEnvironmentBlock(
                out IntPtr lpEnvironment,
                IntPtr hToken,
                bool bInherit);
    
            #endregion
        }
    View Code
    • 第四种方法

    调用方法

    ApplicationLoader.PROCESS_INFORMATION procInfo;
    ApplicationLoader.StartProcessAndBypassUAC(path, out procInfo);//string path=@"C:\Users\Administrator\Test.exe";

    代码类

        /// <summary>
        /// Class that allows running applications with full admin rights. In
        /// addition the application launched will bypass the Vista UAC prompt.
        /// </summary>
        public class ApplicationLoader
        {
    
    
            #region Structrures
    
            [StructLayout(LayoutKind.Sequential)]
            public struct SECURITY_ATTRIBUTES
            {
                public int Length;
                public IntPtr lpSecurityDescriptor;
                public bool bInheritHandle;
            }
    
    
            [StructLayout(LayoutKind.Sequential)]
            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 short wShowWindow;
                public short 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;
            }
    
            #endregion
    
    
            #region Enumberation
            enum TOKEN_TYPE : int
            {
                TokenPrimary = 1,
                TokenImpersonation = 2
            }
    
            enum SECURITY_IMPERSONATION_LEVEL : int
            {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3,
            }
    
            #endregion
    
    
    
    
            #region Constants
    
            public const int TOKEN_DUPLICATE = 0x0002;
            public const uint MAXIMUM_ALLOWED = 0x2000000;
            public const int CREATE_NEW_CONSOLE = 0x00000010;
    
            public const int IDLE_PRIORITY_CLASS = 0x40;
            public const int NORMAL_PRIORITY_CLASS = 0x20;
            public const int HIGH_PRIORITY_CLASS = 0x80;
            public const int REALTIME_PRIORITY_CLASS = 0x100;
    
            #endregion
    
    
    
            #region Win32 API Imports
    
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern bool CloseHandle(IntPtr hSnapshot);
    
            [DllImport("kernel32.dll")]
            static extern uint WTSGetActiveConsoleSessionId();
    
            [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
            public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
               ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
              String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
    
            [DllImport("kernel32.dll")]
            static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);
    
            [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
            public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
                ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
                 int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
    
            [DllImport("kernel32.dll")]
            static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
    
            [DllImport("advapi32.dll", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
            static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
    
            //[DllImport("advapi32.dll", SetLastError = true)]
            //[return: MarshalAs(UnmanagedType.Bool)]
            //static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, ref IntPtr TokenHandle);
    
            #endregion
    
    
    
    
            /// <summary>
            /// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
            /// </summary>
            /// <param name="applicationName">The name of the application to launch</param>
            /// <param name="procInfo">Process information regarding the launched application that gets returned to the caller</param>
            /// <returns></returns>
            public static bool StartProcessAndBypassUAC(String applicationName, out PROCESS_INFORMATION procInfo)
            {
                uint winlogonPid = 0;
                IntPtr hUserTokenDup = IntPtr.Zero,
                    hPToken = IntPtr.Zero,
                    hProcess = IntPtr.Zero;
                procInfo = new PROCESS_INFORMATION();
    
                // obtain the currently active session id; every logged on user in the system has a unique session id
                TSControl.WTS_SESSION_INFO[] pSessionInfo = TSControl.SessionEnumeration();
                uint dwSessionId = 100;
                for (int i = 0; i < pSessionInfo.Length; i++)
                {
                    if (pSessionInfo[i].SessionID != 0)
                    {
                        try
                        {
                            int count = 0;
                            IntPtr buffer = IntPtr.Zero;
                            StringBuilder sb = new StringBuilder();
    
                            bool bsuccess = TSControl.WTSQuerySessionInformation(
                               IntPtr.Zero, pSessionInfo[i].SessionID,
                               TSControl.WTSInfoClass.WTSUserName, out sb, out count);
    
                            if (bsuccess)
                            {
                                if (sb.ToString().Trim() == "Administrator")//Administrator
                                {
                                    dwSessionId = (uint)pSessionInfo[i].SessionID;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            //LoaderService.WriteLog(ex.Message.ToString(), "Monitor");
                        }
                    }
                }
    
                // obtain the process id of the winlogon process that is running within the currently active session
                Process[] processes = Process.GetProcessesByName("explorer");
                foreach (Process p in processes)
                {
                    if ((uint)p.SessionId == dwSessionId)
                    {
                        winlogonPid = (uint)p.Id;
                    }
                }
    
                //LoaderService.WriteLog(winlogonPid.ToString(), "Monitor");
    
                // obtain a handle to the winlogon process
                hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
    
                // obtain a handle to the access token of the winlogon process
                if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
                {
                    CloseHandle(hProcess);
                    return false;
                }
    
                // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
                // I would prefer to not have to use a security attribute variable and to just 
                // simply pass null and inherit (by default) the security attributes
                // of the existing token. However, in C# structures are value types and therefore
                // cannot be assigned the null value.
                SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
                sa.Length = Marshal.SizeOf(sa);
    
                // copy the access token of the winlogon process; the newly created token will be a primary token
                if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
                {
                    CloseHandle(hProcess);
                    CloseHandle(hPToken);
                    return false;
                }
    
                // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
                // the window station has a desktop that is invisible and the process is incapable of receiving
                // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user 
                // interaction with the new process.
                STARTUPINFO si = new STARTUPINFO();
                si.cb = (int)Marshal.SizeOf(si);
                si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
    
                // flags that specify the priority and creation method of the process
                int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
    
                // create a new process in the current user's logon session
                bool result = CreateProcessAsUser(hUserTokenDup,        // client's access token
                                                null,                   // file to execute
                                                applicationName,        // command line
                                                 ref sa,                 // pointer to process SECURITY_ATTRIBUTES
                                                 ref sa,                 // pointer to thread SECURITY_ATTRIBUTES
                                                 false,                  // handles are not inheritable
                                                 dwCreationFlags,        // creation flags
                                                 IntPtr.Zero,            // pointer to new environment block 
                                                 null,                   // name of current directory 
                                                 ref si,                 // pointer to STARTUPINFO structure
                                                 out procInfo            // receives information about new process
                                                 );
    
                // invalidate the handles
                CloseHandle(hProcess);
                CloseHandle(hPToken);
                CloseHandle(hUserTokenDup);
                //LoaderService.WriteLog("launch Task", "Monitor");
    
                return result; // return the result
            }
    
        }
    View Code
     public class TSControl
        {
            /**/
            /// <summary> 
            /// Terminal Services API Functions,The WTSEnumerateSessions function retrieves a list of sessions on a specified terminal server, 
            /// </summary> 
            /// <param name="hServer">[in] Handle to a terminal server. Specify a handle opened by the WTSOpenServer function, or specify WTS_CURRENT_SERVER_HANDLE to indicate the terminal server on which your application is running</param> 
            /// <param name="Reserved">Reserved; must be zero</param> 
            /// <param name="Version">[in] Specifies the version of the enumeration request. Must be 1. </param> 
            /// <param name="ppSessionInfo">[out] Pointer to a variable that receives a pointer to an array of WTS_SESSION_INFO structures. Each structure in the array contains information about a session on the specified terminal server. To free the returned buffer, call the WTSFreeMemory function. 
            /// To be able to enumerate a session, you need to have the Query Information permission.</param> 
            /// <param name="pCount">[out] Pointer to the variable that receives the number of WTS_SESSION_INFO structures returned in the ppSessionInfo buffer. </param> 
            /// <returns>If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero</returns> 
            [DllImport("wtsapi32", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool WTSEnumerateSessions(int hServer, int Reserved, int Version, ref long ppSessionInfo, ref int pCount);
    
            /**/
            /// <summary> 
            /// Terminal Services API Functions,The WTSFreeMemory function frees memory allocated by a Terminal Services function. 
            /// </summary> 
            /// <param name="pMemory">[in] Pointer to the memory to free</param> 
            [DllImport("wtsapi32.dll")]
            public static extern void WTSFreeMemory(System.IntPtr pMemory);
    
            /**/
            /// <summary> 
            /// Terminal Services API Functions,The WTSLogoffSession function logs off a specified Terminal Services session. 
            /// </summary> 
            /// <param name="hServer">[in] Handle to a terminal server. Specify a handle opened by the WTSOpenServer function, or specify WTS_CURRENT_SERVER_HANDLE to indicate the terminal server on which your application is running. </param> 
            /// <param name="SessionId">[in] A Terminal Services session identifier. To indicate the current session, specify WTS_CURRENT_SESSION. You can use the WTSEnumerateSessions function to retrieve the identifiers of all sessions on a specified terminal server. 
            /// To be able to log off another user's session, you need to have the Reset permission </param> 
            /// <param name="bWait">[in] Indicates whether the operation is synchronous. 
            /// If bWait is TRUE, the function returns when the session is logged off. 
            /// If bWait is FALSE, the function returns immediately.</param> 
            /// <returns>If the function succeeds, the return value is a nonzero value. 
            /// If the function fails, the return value is zero.</returns> 
            [DllImport("wtsapi32.dll")]
            public static extern bool WTSLogoffSession(int hServer, long SessionId, bool bWait);
    
    
            [DllImport("Wtsapi32.dll")]
            public static extern bool WTSQuerySessionInformation(
                System.IntPtr hServer,
                int sessionId,
                WTSInfoClass wtsInfoClass,
                out StringBuilder ppBuffer,
                out int pBytesReturned
                );
    
            public enum WTSInfoClass
            {
                WTSInitialProgram,
                WTSApplicationName,
                WTSWorkingDirectory,
                WTSOEMId,
                WTSSessionId,
                WTSUserName,
                WTSWinStationName,
                WTSDomainName,
                WTSConnectState,
                WTSClientBuildNumber,
                WTSClientName,
                WTSClientDirectory,
                WTSClientProductId,
                WTSClientHardwareId,
                WTSClientAddress,
                WTSClientDisplay,
                WTSClientProtocolType
            }
    
            /**/
            /// <summary> 
            /// The WTS_CONNECTSTATE_CLASS enumeration type contains INT values that indicate the connection state of a Terminal Services session. 
            /// </summary> 
            public enum WTS_CONNECTSTATE_CLASS
            {
                WTSActive,
                WTSConnected,
                WTSConnectQuery,
                WTSShadow,
                WTSDisconnected,
                WTSIdle,
                WTSListen,
                WTSReset,
                WTSDown,
                WTSInit,
            }
    
    
            /**/
            /// <summary> 
            /// The WTS_SESSION_INFO structure contains information about a client session on a terminal server. 
            /// if the WTS_SESSION_INFO.SessionID==0, it means that the SESSION is the local logon user's session. 
            /// </summary> 
            public struct WTS_SESSION_INFO
            {
                public int SessionID;
                [MarshalAs(UnmanagedType.LPTStr)]
                public string pWinStationName;
                public WTS_CONNECTSTATE_CLASS state;
            }
    
            /**/
            /// <summary> 
            /// The SessionEnumeration function retrieves a list of 
            ///WTS_SESSION_INFO on a current terminal server. 
            /// </summary> 
            /// <returns>a list of WTS_SESSION_INFO on a current terminal server</returns> 
            public static WTS_SESSION_INFO[] SessionEnumeration()
            {
                //Set handle of terminal server as the current terminal server 
                int hServer = 0;
                bool RetVal;
                long lpBuffer = 0;
                int Count = 0;
                long p;
                WTS_SESSION_INFO Session_Info = new WTS_SESSION_INFO();
                WTS_SESSION_INFO[] arrSessionInfo;
                RetVal = WTSEnumerateSessions(hServer, 0, 1, ref lpBuffer, ref Count);
                arrSessionInfo = new WTS_SESSION_INFO[0];
                if (RetVal)
                {
                    arrSessionInfo = new WTS_SESSION_INFO[Count];
                    int i;
                    p = lpBuffer;
                    for (i = 0; i < Count; i++)
                    {
                        arrSessionInfo[i] =
                            (WTS_SESSION_INFO)Marshal.PtrToStructure(new IntPtr(p),
                            Session_Info.GetType());
                        p += Marshal.SizeOf(Session_Info.GetType());
                    }
                    WTSFreeMemory(new IntPtr(lpBuffer));
                }
                else
                {
                    //Insert Error Reaction Here 
                }
                return arrSessionInfo;
            }
    
            public TSControl()
            {
                // 
                // TODO: 在此处添加构造函数逻辑 
                // 
    
            }
    
    
        }
    View Code
    • 参考资料

          https://blog.csdn.net/peter_666/article/details/8106273

          https://www.cnblogs.com/gnielee/archive/2010/04/08/session0-isolation-part2.html

          https://www.cnblogs.com/qiaoke/p/6654449.html

          https://www.cnblogs.com/datacool/p/CreateProcessAsUser_Win_api.html

          https://blog.csdn.net/vevisoft/article/details/42751533

  • 相关阅读:
    笔记:C/C++字符函数的使用
    学习游戏基础编程3:地图编辑器
    学习游戏基础编程2:Win32分割窗口
    学习游戏基础编程1:Win32自定义控件
    [WebServer] Tomcat 配置访问限制:访问白名单和访问黑名单
    [WebServer] Windows操作系统下 Tomcat 服务器运行 PHP 的环境配置
    XSLT函数集合:数值函数、字符串函、节点集函数和布尔函数
    腾讯的一道JavaScript面试题
    【转】AES 进一步的研究
    MQTT-Client-FrameWork使用整理
  • 原文地址:https://www.cnblogs.com/CityOfThousandFires/p/10375242.html
Copyright © 2011-2022 走看看