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 = 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/484190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谈谈相控阵雷达为何如此先进

作者&#xff1a;寒木钓萌来源&#xff1a;电子万花筒对于很多人来说&#xff0c;相控阵雷达非常耳熟&#xff0c;但它的原理又是什么呢&#xff1f;传统雷达与相控阵雷达之区别要说相控阵雷达的原理&#xff0c;就不得不提一下传统雷达的工作方式。影视中&#xff0c;如果非要…

华为在5.5G未来技术演进的六个方向!

来源&#xff1a;5G产业园”2021年8月3日&#xff0c;华为和中国移动在北京召开主题为“双链融合&#xff0c;共创5G可持续发展未来”的5G-Advanced创新产业峰会。华为常务董事、ICT产品与解决方案总裁汪涛在峰会上发表了“合作创新&#xff0c;5.5G使能万物智联”的主题演讲&a…

引用传递

引用传递的核心意义&#xff1a; 同一块堆内存空间可以被不同的栈内存所指向&#xff0c;不同的栈内存可以对同一个堆内存进行内容的修改。 实例1&#xff1a; class Message {private int num 10;public Message(int num){this.num num; //2.this是代表msg这个对象&#…

线程知识点(一)—— 程序、进程、线程之间的区别与联系、Java的线程状态和生命周期

1 程序、进程、线程之间的区别与联系 三者之间的形象化理解&#xff1a; * 程序&#xff1a;代码实现了功能&#xff0c;就是程序&#xff0c;是静态的&#xff1b; * 进程&#xff1a;执行中的程序就是进程&#xff0c;是动态的&#xff1b; * 线程&#xff1a;进程内的一个执…

官方全面解读“5G+工业互联网”

来源&#xff1a;工信部网站未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体系&#xff0c;开展世界人工智能智商评测&#xff1b;开展互联网&#xff08;城市&#xff09;大脑研究计划&#xff0c;构建互联网&#xff08;城市&#xff09;大脑技术和企业图…

为什么要学数学?因为这是一场战略性的投资

来源&#xff1a;数学内参如果将数学学习的好坏仅仅理解为“刷题”的数量和速度&#xff0c;那充其量也只能成为一名熟练的数学工匠。我们所受的数学训练&#xff0c;所领会的数学思想和精神&#xff0c;所获得的数学教养&#xff0c;无时无刻不在发挥着积极的作用&#xff0c;…

滤波 放电速度比充电慢 模电

我不理解为什么这里放电速度比充电速度慢&#xff1f; 因为充电时间常数小&#xff0c;而放电时间常数大 转载于:https://www.cnblogs.com/china520/p/10389477.html

Hexo如何绑定个人域名

前两天用HexoGitHub搭建好了自己的个人博客https://www.serendipper-x.cn/&#xff0c;默认域名github下的二级域名&#xff1a;username.github.io&#xff0c;为了提升访问速度和博客的格调&#xff0c;绑定个人域名是多数人的选择。下面给大家介绍详细过程。 购买域名 国内…

什么是涌现?

来源&#xff1a;集智俱乐部作者&#xff1a;由集智俱乐部众包生产在哲学、系统论、科学和艺术中&#xff0c;当一个实体被观察到具有其所有组成部分本身没有的属性时&#xff0c;涌现 emergence 就出现了。这些属性或行为只有当各个部分在一个更广泛的整体中相互作用时才会涌现…

人工智能vs人类智能小传

来源&#xff1a;混沌巡洋舰Alphago代表的深度网络人工智能体现了AI逐步进入未知领域的强大能力&#xff0c; 因此有人堪忧有人喜乐&#xff0c; 却极少有人戳中要害。说AI比人牛是因为它下围棋比人厉害&#xff1f; 说AI离真正的智能很遥远是因为它不能创造吗&#xff1f; 是…

IDEA换行CRLF, LF, CR的解释和默认设置

在window下开发有一个大坑&#xff0c;就是换行默认是CRLF&#xff0c;也就是回车换行&#xff0c;但是Linux下只有换行LF&#xff0c;这样代码提交后&#xff0c;会出现编译问题&#xff0c;所以最好的办法是在IDEA下设置默认为LF。 首先我们先介绍CRLF&#xff0c;LF和CR这三…

云数据库

一.概述 1.1 云计算通过网络以服务的方式为用户提供廉价的资源。 1.2 优势 按需服务&#xff1b;随时服务&#xff1b;通用性&#xff1b;高可靠性&#xff1a;冗余备份&#xff1b;成本低&#xff0c;廉价&#xff1b;超大规模&#xff1b;虚拟化&#xff1b;扩展性高&#…

一个困扰数学家30多年的分类问题,终于被解决了!

来源&#xff1a;AI科技评论作者&#xff1a;Steve Nadis编译&#xff1a;陈彩娴编辑&#xff1a;青暮一般情况下&#xff0c;当你要对某个特定地区的植物进行调查时&#xff0c;你可能会按植物的种类来划分。就这种方法来看&#xff0c;如果是沿着托斯卡纳海岸的某些地带做这类…

欢迎参加“城市大脑与应急管理”专家研讨会

来源&#xff1a;城市大脑全球标准研究组数字大脑学术系列沙龙第二期“城市大脑与应急管理”专家研讨会2021以来城市大脑的建设与研究获得了长足发展&#xff0c;数百个城市开展了城市大脑的建设与规划&#xff0c;取得了诸多成果。于此同时&#xff0c;伴随着疫情、水灾、交通…

MapReduce词频统计

1.1 文件准备 创建本地目录和创建两个文本文件&#xff0c;在两个文件中输入单词&#xff0c;用于统计词频。 cd /usr/local/hadoop mkdir WordFile cd WordFile touch wordfile1.txt touch wordfile2.txt1.2 创建一个HDFS目录&#xff0c;在本地上不可见,并将本地文本文件上传…

Spring中注解大全

Spring中注解大全 Controller 标识一个该类是Spring MVC controller 处理器&#xff0c;用来创建处理http请求的对象 Controller public class TestController{RequestMapping("test")public String test(Map<String,Object> map){return "hello"…

Linux系统组成

1 系统组成 BootLoader&#xff1a;操作系统引导程序 内核&#xff1a; 文件系统&#xff1a;应用程序(用户开发的、网上下载的) 2 安装USB驱动 dongryd-linux:~$ insmod usb_dnw.ko //安装USB驱动 dongryd-linux:~$ kernel:GuoQian USB driver for DMW! //出现这一句说明驱动…

使用github托管代码以及github一些最常用的命令

生成SSH密钥 首先打开命令行工具&#xff0c;右键鼠标任意位置打开git bash here,然后输入以下命令 cd ~/.ssh 使用ssh-keygen生成密钥 ssh-keygen -t rsa -C "我的邮箱地址" 使用默认的文件名&#xff0c;输入密码&#xff0c;密钥生成成功 直接复制命令行看到的密钥…

Hive安装与配置MySQL元数据库

一.MySQL的安装 1.1 更新获取最新软件源&#xff0c;并安装MySQL。 sudo apt-get update sudo apt-get install mysql-server1.2 启动和关闭MySQL服务器。 service mysql start service mysql stop1.3 确认MySQL 是否启动成功&#xff0c;MySQL 处于LISTEN状态则表示启动成功…

国际领先的人工智能团队值得我们学习和深思

‍来源&#xff1a;陈德旺科学网博客链接地址&#xff1a;http://blog.sciencenet.cn/blog-57940-1299162.html如其说&#xff0c;人工智能&#xff08;AI&#xff09;现今热潮是Hinton等图灵奖获得者引发的&#xff0c;不如说是DeepMind&#xff08;深度思考&#xff0c;简称深…