在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 APIsprivate 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 Enumberationenum TOKEN_TYPE : int{TokenPrimary = 1,TokenImpersonation = 2}enum SECURITY_IMPERSONATION_LEVEL : int{SecurityAnonymous = 0,SecurityIdentification = 1,SecurityImpersonation = 2,SecurityDelegation = 3,}#endregion#region Constantspublic 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 idTSControl.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 sessionProcess[] 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 processhProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);// obtain a handle to the access token of the winlogon processif (!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 tokenif (!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 processint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;// create a new process in the current user's logon sessionbool result = CreateProcessAsUser(hUserTokenDup,        // client's access tokennull,                   // file to executeapplicationName,        // command lineref sa,                 // pointer to process SECURITY_ATTRIBUTESref sa,                 // pointer to thread SECURITY_ATTRIBUTESfalse,                  // handles are not inheritabledwCreationFlags,        // creation flagsIntPtr.Zero,            // pointer to new environment block null,                   // name of current directory ref si,                 // pointer to STARTUPINFO structureout 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

转载于:https://www.cnblogs.com/CityOfThousandFires/p/10375242.html

C#穿透session隔离———Windows服务启动UI交互程序相关推荐

  1. C# windows服务启动winform应用程序

    最近在写一个守护进程的服务,遇到了一点儿问题,现在记录下来,也希望能帮到有需要的人. 开发环境:win7,VS2015 问题: 1.通过process启动App,不显示界面 2.有的电脑安装服务Ser ...

  2. Windows服务启动进程----Cjwdev.WindowsApi.dll

    windows服务下无法启动外部程序 做一个windows服务监听服务,涉及到windows服务启动外部程序的一个过程,但是调试测试发现,无法简单的用process.start()这种方法, 原因是在 ...

  3. python开发服务程序_Python 编写Windows服务程序:将Python作为Windows服务启动 | 学步园...

    Python程序作为Windows服务启动,需要安装pywin32包.下载路径: #-*- coding:utf-8 -*- import win32serviceutil import win32s ...

  4. windows服务启动路径修改方法

    ** windows服务启动路径修改方法 1.进入服务,查看路径,[开始]=>[运行]=>[services.msc] 2.进入注册表,修改服务路径[开始]=>[运行]=>[r ...

  5. windows服务启动失败解决流程

    最近遇到windows服务启动失败的情况,网上查阅了一下相关的解决方式,顺便记录一下解决的一般流程和方式: (一般是软件的配置文件出现问题,先检查配置文件是否有问题,例如没有符合yml格式(不可使用t ...

  6. windows 服务启动失败的解决办法

    标签: windows 服务启动失败的解决办法 当启动服务失败,原因往往在于用户更改了用户名或者密码所引起. 今天我遇到该问题是我改了系统管理员密码后碰到的,在我该了系统管理员密码后启动postgre ...

  7. mongodb配置windows服务启动

    第一步 下载MongoDB http://www.mongodb.org/downloads 第二步 解压到D:\mongodb\目录下,为了命令行的方便,可以把D:\mongodb\bin加到系统环 ...

  8. java web windows_WinSW让你的JavaWEB程序作为Windows服务启动!

    概述 WinSW is an executable binary, which can be used to wrap and manage a custom process as a Windows ...

  9. 使用Windows服务启动C#桌面应用程序问题解决

    一.背景 为了实现Windows应用程序开机自启动,使用了Windows服务技术后台运行.这里遇到了以下问题 二.问题点及解决 1.使用Process.start()出现不生效问题. 现象:启动服务后 ...

最新文章

  1. phoenixframework自动化测试平台架构图
  2. Java 类的一些高级特征
  3. 云计算网络基础第八天
  4. lenovo服务器换系统重装系统_如何给lenovo电脑重装系统 lenovo电脑重装系统步骤...
  5. _tcsnicmp_wcsnicmp
  6. bzoj1202[HNOI2005]狡猾的商人
  7. 富士通01018z平板电脑评测_档案扫描好帮手,富士通ix1500无线双面高速扫描仪评测...
  8. chrome稍后阅读功能reading list
  9. python 2.7 input_Python2.7-fileinput
  10. 从学校到职场的路有多远
  11. 用hadoop运行一个简单程序WordCount
  12. [ActionScript 3.0] AS3.0 把图片分析成文本表现形式
  13. 腾讯产培课堂|产品经理岗位解析×面试指南
  14. 小程序公众图标素材6113个菜单栏素材
  15. 直播/点播系统快速搭建指南
  16. Java实现牛牛算法详解
  17. paypal支付(Java)
  18. springboot+MyBatis返回Map时值为null的字段会丢失
  19. 【水果识别】基于形态学实现水果识别含Matlab源码
  20. 小技巧 - 如何将“比例比例”站上的视频下载到本地?

热门文章

  1. 计算机硬件知识考证题,计算机硬件知识题(答案)资料
  2. 中缀表达式转换为前缀及后缀表达式并求值【摘】
  3. python中内置的集成开发工具_python应用(3):启用集成开发工具pycharm
  4. 核酸结果统计难?130行代码实现基于ocr的核酸截图识别存储Excel(复现代码核查核酸报告)
  5. 【Pytorch神经网络理论篇】 15 过拟合问题的优化技巧(二):Dropout()方法
  6. LeetCode 900. RLE 迭代器(模拟/二分查找)
  7. LeetCode 259. 较小的三数之和(固定一点,内层双指针)
  8. LeetCode 720. 词典中最长的单词(Trie树)
  9. 刷新页面,无论点击多少次让Element UI的Message消息提示弹出一个
  10. python 经典100例 (61-80)