C#穿透session隔离———Windows服务启动UI交互程序
在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 = ;
- WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), title, title.Length, message, message.Length, , , 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 = ;
- if (WTSEnumerateSessions(
- (IntPtr)WTS_CURRENT_SERVER_HANDLE, // Current RD Session Host Server handle would be zero.
- , // This reserved parameter must be zero.
- , // 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 = ; 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.
- , // 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);
- }
- }
- }
- 第二种方法
调用方法
- 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 = ;// 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, , 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 = ,
- 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 = ;
- WTSSendMessage(
- WTS_CURRENT_SERVER_HANDLE,
- WTSGetActiveConsoleSessionId(),
- title, title.Length,
- message, message.Length,
- , , 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);
- }
- 第三种方法(可以远程)
调用方法
- SessionUtility.CreateProcess(@"C:\Windows\System32\", path, );//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 = ;
- WTSSendMessage(
- WTS_CURRENT_SERVER_HANDLE,
- WTSGetActiveConsoleSessionId(),
- title, title.Length,
- message, message.Length,
- , , 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 < )
- 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, , 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 = ,
- 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
- }
- 第四种方法
调用方法
- 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 = ,
- TokenImpersonation =
- }
- enum SECURITY_IMPERSONATION_LEVEL : int
- {
- SecurityAnonymous = ,
- SecurityIdentification = ,
- SecurityImpersonation = ,
- SecurityDelegation = ,
- }
- #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 = ;
- 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 = ;
- for (int i = ; i < pSessionInfo.Length; i++)
- {
- if (pSessionInfo[i].SessionID != )
- {
- try
- {
- int count = ;
- 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
- }
- }
- 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 = ;
- bool RetVal;
- long lpBuffer = ;
- int Count = ;
- long p;
- WTS_SESSION_INFO Session_Info = new WTS_SESSION_INFO();
- WTS_SESSION_INFO[] arrSessionInfo;
- RetVal = WTSEnumerateSessions(hServer, , , ref lpBuffer, ref Count);
- arrSessionInfo = new WTS_SESSION_INFO[];
- if (RetVal)
- {
- arrSessionInfo = new WTS_SESSION_INFO[Count];
- int i;
- p = lpBuffer;
- for (i = ; 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: 在此处添加构造函数逻辑
- //
- }
- }
- 参考资料
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#穿透session隔离———Windows服务启动UI交互程序的更多相关文章
- windows服务启动有界面的程序
大家写windows服务守护进程的时候,肯定会遇到启动的程序看不到界面,只能在任务管理器里面看到xxx.exe问题. 发现可能有如下情况 a.无论是开机,还是程序被关掉后,守护服务启动的程序只能看到任 ...
- Windows服务启动进程----Cjwdev.WindowsApi.dll
windows服务下无法启动外部程序 做一个windows服务监听服务,涉及到windows服务启动外部程序的一个过程,但是调试测试发现,无法简单的用process.start()这种方法, 原因是在 ...
- MongoDB做为一项windows服务启动
MongoDB做为一项windows服务启动 Windows版本安装 MongoDB的官方下载站是http://www.mongodb.org/downloads,可以去上面下载最新的对应版本,有32 ...
- 玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案
将VS创建的Windows服务项目编译生成的程序,通过命令行 “服务.exe -Service”注册为Windows服务后,就可以通过服务管理器进行管理了. 问题 通过服务管理器进行启动的时候,发现服 ...
- 玩转Windows服务系列——Windows服务启动超时时间
最近有客户反映,机房出现断电情况,服务器的系统重新启动后,数据库服务自启动失败.第一次遇到这种情况,为了查看是不是断电情况导致数据库文件损坏,从客户的服务器拿到数据库的日志,进行分析. 数据库工作机制 ...
- C#判断程序是由Windows服务启动还是用户启动
在Windows系统做网络开发,很多时候都是使用Windows服务的模式,但在调度阶段,我们更多的是使用控制台的模式.在开发程序的时候,我们在Program的Main入口进行判断.最初开始使用Envi ...
- windows服务启动 1053错误
1.问题描述 今天在启动一个Windows服务时,服务启动不了,且提示:1053错误 那么是什么导致了1053错误呢? 2.他山之石 百度了一下,发现有人作出下面的解释并给出了解决方法: “常常是因为 ...
- Redis Windows 服务启动异常 错误码1067
https://blog.csdn.net/after_you/article/details/62215163 Redis Windows 服务启动异常 错误码1067 下载了Redis 2.8.2 ...
- C# windows服务,解决应用程序开机自启问题
最近在东营做一个超市购物的项目,业务体量很小,是仅供内部员工使用的内网应用程序,其中涉及一个商品数据同步的winform应用程序,有一个问题就是服务器重启后,必须登录服务器操作系统,手动启动才行,于是 ...
随机推荐
- 排序矩阵中的从小到大第k个数 · Kth Smallest Number In Sorted Matrix
[抄题]: 在一个排序矩阵中找从小到大的第 k 个整数. 排序矩阵的定义为:每一行递增,每一列也递增. [思维问题]: 不知道应该怎么加,因为不是一维单调的. [一句话思路]: 周围两个数给x或y挪一 ...
- 通过BeanShell获取UUID并将参数传递给Jmeter
有些HTTPS请求报文的报文体中包含由客户端生成的UUID,在用Jmeter做接口自动化测试的时候,因为越过了客户端,直接向服务器端发送报文,所以,需要在Jmeter中通过beanshell获取UUI ...
- 2018.10.16 NOIP模拟 华莱士(并查集)
传送门 按照题意模拟维护最小的环套树森林就行了. 然而考试的时候naivenaivenaive瞎写了一个错误的贪心. 代码
- 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)
3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...
- org.eclipse.ui.PartInitException: Unable to open editor, unknown editor ID: org.xmen.ui.text.XMLTextEditor
无法打开struts模式的编译xml的编译器,然后打开.project文件,编辑最后一行,找到<natures>结点,增加一条<nature>com.genuitec.ecli ...
- (KMP)Seek the Name, Seek the Fame -- poj --2752
http://poj.org/problem?id=2752 Seek the Name, Seek the Fame Time Limit: 2000MS Memory Limit: 65536 ...
- java基础-day4
第04天 java基础语法 今日内容介绍 u Random u 数组 第1章 Random 1.1 产生整数随机数 1.1.1 Random的使用步骤 我们想产生1~100(包含1 ...
- 『IOS』 遇到问题记录(长期更新)
遇到的很多问题,解决后都是自己记着,以为不会忘记,之后却会想不起来了. 所以把今后解决的问题记录在这. 一. 在二级页面设置了CAlayer的代理,在返回一级页面报错: EXC_BAD_ACCESS( ...
- eclipse快捷键(增加一些4连组合快捷键)
http://www.blogjava.net/i369/articles/83309.html ECLISPE的快捷键大全 Eclipse 常用快捷键收集2006年09月29日 星期五 12:0 ...
- svn服务器快速搭建及简单配置
http://www.360doc.com/content/11/0711/19/5131531_132950891.shtml 简介Svn已经不容质疑的成为了一款流行的代码控制工具,但是你是否还在为 ...