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

需要注意的地方

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

       

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

 

实现代码如下

  • 第一种方法

调用方法

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

代码类

  1. public class WinAPI_Interop
  2. {
  3. public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
  4. /// <summary>
  5. /// 服务程序执行消息提示,前台MessageBox.Show
  6. /// </summary>
  7. /// <param name="message">消息内容</param>
  8. /// <param name="title">标题</param>
  9. public static void ShowServiceMessage(string message, string title)
  10. {
  11. int resp = ;
  12. WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), title, title.Length, message, message.Length, , , out resp, false);
  13. }
  14.  
  15. [DllImport("kernel32.dll", SetLastError = true)]
  16. public static extern int WTSGetActiveConsoleSessionId();
  17.  
  18. [DllImport("wtsapi32.dll", SetLastError = true)]
  19. 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);
  20. #region P/Invoke WTS APIs
  21. private enum WTS_CONNECTSTATE_CLASS
  22. {
  23. WTSActive,
  24. WTSConnected,
  25. WTSConnectQuery,
  26. WTSShadow,
  27. WTSDisconnected,
  28. WTSIdle,
  29. WTSListen,
  30. WTSReset,
  31. WTSDown,
  32. WTSInit
  33. }
  34.  
  35. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  36. private struct WTS_SESSION_INFO
  37. {
  38. public UInt32 SessionID;
  39. public string pWinStationName;
  40. public WTS_CONNECTSTATE_CLASS State;
  41. }
  42.  
  43. [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
  44. static extern bool WTSEnumerateSessions(
  45. IntPtr hServer,
  46. [MarshalAs(UnmanagedType.U4)] UInt32 Reserved,
  47. [MarshalAs(UnmanagedType.U4)] UInt32 Version,
  48. ref IntPtr ppSessionInfo,
  49. [MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount
  50. );
  51.  
  52. [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
  53. static extern void WTSFreeMemory(IntPtr pMemory);
  54.  
  55. [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
  56. static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
  57. #endregion
  58.  
  59. #region P/Invoke CreateProcessAsUser
  60. /// <summary>
  61. /// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser.
  62. /// </summary>
  63. ///
  64.  
  65. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  66. struct STARTUPINFO
  67. {
  68. public Int32 cb;
  69. public string lpReserved;
  70. public string lpDesktop;
  71. public string lpTitle;
  72. public Int32 dwX;
  73. public Int32 dwY;
  74. public Int32 dwXSize;
  75. public Int32 dwYSize;
  76. public Int32 dwXCountChars;
  77. public Int32 dwYCountChars;
  78. public Int32 dwFillAttribute;
  79. public Int32 dwFlags;
  80. public Int16 wShowWindow;
  81. public Int16 cbReserved2;
  82. public IntPtr lpReserved2;
  83. public IntPtr hStdInput;
  84. public IntPtr hStdOutput;
  85. public IntPtr hStdError;
  86. }
  87.  
  88. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  89. struct PROCESS_INFORMATION
  90. {
  91. public IntPtr hProcess;
  92. public IntPtr hThread;
  93. public int dwProcessId;
  94. public int dwThreadId;
  95. }
  96.  
  97. /// <summary>
  98. /// 以当前登录的windows用户(角色权限)运行指定程序进程
  99. /// </summary>
  100. /// <param name="hToken"></param>
  101. /// <param name="lpApplicationName">指定程序(全路径)</param>
  102. /// <param name="lpCommandLine">参数</param>
  103. /// <param name="lpProcessAttributes">进程属性</param>
  104. /// <param name="lpThreadAttributes">线程属性</param>
  105. /// <param name="bInheritHandles"></param>
  106. /// <param name="dwCreationFlags"></param>
  107. /// <param name="lpEnvironment"></param>
  108. /// <param name="lpCurrentDirectory"></param>
  109. /// <param name="lpStartupInfo">程序启动属性</param>
  110. /// <param name="lpProcessInformation">最后返回的进程信息</param>
  111. /// <returns>是否调用成功</returns>
  112. [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
  113. static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,
  114. bool bInheritHandles, uint dwCreationFlags, string lpEnvironment, string lpCurrentDirectory,
  115. ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
  116.  
  117. [DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
  118. static extern bool CloseHandle(IntPtr hHandle);
  119. #endregion
  120.  
  121. /// <summary>
  122. /// 以当前登录系统的用户角色权限启动指定的进程
  123. /// </summary>
  124. /// <param name="ChildProcName">指定的进程(全路径)</param>
  125. public static void CreateProcess(string ChildProcName)
  126. {
  127. IntPtr ppSessionInfo = IntPtr.Zero;
  128. UInt32 SessionCount = ;
  129. if (WTSEnumerateSessions(
  130. (IntPtr)WTS_CURRENT_SERVER_HANDLE, // Current RD Session Host Server handle would be zero.
  131. , // This reserved parameter must be zero.
  132. , // The version of the enumeration request must be 1.
  133. ref ppSessionInfo, // This would point to an array of session info.
  134. ref SessionCount // This would indicate the length of the above array.
  135. ))
  136. {
  137. for (int nCount = ; nCount < SessionCount; nCount++)
  138. {
  139. WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)), typeof(WTS_SESSION_INFO));
  140. if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
  141. {
  142. IntPtr hToken = IntPtr.Zero;
  143. if(WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
  144. {
  145. PROCESS_INFORMATION tProcessInfo;
  146. STARTUPINFO tStartUpInfo = new STARTUPINFO();
  147. tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
  148. bool ChildProcStarted = CreateProcessAsUser(
  149. hToken, // Token of the logged-on user.
  150. ChildProcName, // Name of the process to be started.
  151. null, // Any command line arguments to be passed.
  152. IntPtr.Zero, // Default Process' attributes.
  153. IntPtr.Zero, // Default Thread's attributes.
  154. false, // Does NOT inherit parent's handles.
  155. , // No any specific creation flag.
  156. null, // Default environment path.
  157. null, // Default current directory.
  158. ref tStartUpInfo, // Process Startup Info.
  159. out tProcessInfo // Process information to be returned.
  160. );
  161. if (ChildProcStarted)
  162. {
  163. CloseHandle(tProcessInfo.hThread);
  164. CloseHandle(tProcessInfo.hProcess);
  165. }
  166. else
  167. {
  168. ShowServiceMessage("CreateProcessAsUser失败", "CreateProcess");
  169. }
  170. CloseHandle(hToken);
  171. break;
  172. }
  173. }
  174. }
  175. WTSFreeMemory(ppSessionInfo);
  176. }
  177. }
  178. }
  • 第二种方法

调用方法

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

代码类

  1. public class Interops
  2. {
  3. public static void CreateProcess(string app, string path)
  4. {
  5. bool result;
  6. IntPtr hToken = WindowsIdentity.GetCurrent().Token;
  7. IntPtr hDupedToken = IntPtr.Zero;
  8.  
  9. PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
  10. SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
  11. sa.Length = Marshal.SizeOf(sa);
  12.  
  13. STARTUPINFO si = new STARTUPINFO();
  14. si.cb = Marshal.SizeOf(si);
  15.  
  16. int dwSessionID = ;// WTSGetActiveConsoleSessionId();
  17. result = WTSQueryUserToken(dwSessionID, out hToken);
  18.  
  19. if (!result)
  20. {
  21. ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
  22. }
  23.  
  24. result = DuplicateTokenEx(
  25. hToken,
  26. GENERIC_ALL_ACCESS,
  27. ref sa,
  28. (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
  29. (int)TOKEN_TYPE.TokenPrimary,
  30. ref hDupedToken
  31. );
  32.  
  33. if (!result)
  34. {
  35. ShowMessageBox("DuplicateTokenEx failed", "AlertService Message");
  36. }
  37.  
  38. IntPtr lpEnvironment = IntPtr.Zero;
  39. result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
  40.  
  41. if (!result)
  42. {
  43. ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
  44. }
  45.  
  46. result = CreateProcessAsUser(
  47. hDupedToken,
  48. app,
  49. String.Empty,
  50. ref sa, ref sa,
  51. false, , IntPtr.Zero,
  52. null, ref si, ref pi);
  53.  
  54. if (!result)
  55. {
  56. int error = Marshal.GetLastWin32Error();
  57. string message = String.Format("CreateProcessAsUser Error: {0}", error);
  58. ShowMessageBox(message, "AlertService Message");
  59. }
  60.  
  61. if (pi.hProcess != IntPtr.Zero)
  62. CloseHandle(pi.hProcess);
  63. if (pi.hThread != IntPtr.Zero)
  64. CloseHandle(pi.hThread);
  65. if (hDupedToken != IntPtr.Zero)
  66. CloseHandle(hDupedToken);
  67. }
  68.  
  69. [StructLayout(LayoutKind.Sequential)]
  70. public struct STARTUPINFO
  71. {
  72. public Int32 cb;
  73. public string lpReserved;
  74. public string lpDesktop;
  75. public string lpTitle;
  76. public Int32 dwX;
  77. public Int32 dwY;
  78. public Int32 dwXSize;
  79. public Int32 dwXCountChars;
  80. public Int32 dwYCountChars;
  81. public Int32 dwFillAttribute;
  82. public Int32 dwFlags;
  83. public Int16 wShowWindow;
  84. public Int16 cbReserved2;
  85. public IntPtr lpReserved2;
  86. public IntPtr hStdInput;
  87. public IntPtr hStdOutput;
  88. public IntPtr hStdError;
  89. }
  90.  
  91. [StructLayout(LayoutKind.Sequential)]
  92. public struct PROCESS_INFORMATION
  93. {
  94. public IntPtr hProcess;
  95. public IntPtr hThread;
  96. public Int32 dwProcessID;
  97. public Int32 dwThreadID;
  98. }
  99.  
  100. [StructLayout(LayoutKind.Sequential)]
  101. public struct SECURITY_ATTRIBUTES
  102. {
  103. public Int32 Length;
  104. public IntPtr lpSecurityDescriptor;
  105. public bool bInheritHandle;
  106. }
  107.  
  108. public enum SECURITY_IMPERSONATION_LEVEL
  109. {
  110. SecurityAnonymous,
  111. SecurityIdentification,
  112. SecurityImpersonation,
  113. SecurityDelegation
  114. }
  115.  
  116. public enum TOKEN_TYPE
  117. {
  118. TokenPrimary = ,
  119. TokenImpersonation
  120. }
  121.  
  122. public const int GENERIC_ALL_ACCESS = 0x10000000;
  123.  
  124. [DllImport("kernel32.dll", SetLastError = true,
  125. CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  126. public static extern bool CloseHandle(IntPtr handle);
  127.  
  128. [DllImport("advapi32.dll", SetLastError = true,
  129. CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  130. public static extern bool CreateProcessAsUser(
  131. IntPtr hToken,
  132. string lpApplicationName,
  133. string lpCommandLine,
  134. ref SECURITY_ATTRIBUTES lpProcessAttributes,
  135. ref SECURITY_ATTRIBUTES lpThreadAttributes,
  136. bool bInheritHandle,
  137. Int32 dwCreationFlags,
  138. IntPtr lpEnvrionment,
  139. string lpCurrentDirectory,
  140. ref STARTUPINFO lpStartupInfo,
  141. ref PROCESS_INFORMATION lpProcessInformation);
  142.  
  143. [DllImport("advapi32.dll", SetLastError = true)]
  144. public static extern bool DuplicateTokenEx(
  145. IntPtr hExistingToken,
  146. Int32 dwDesiredAccess,
  147. ref SECURITY_ATTRIBUTES lpThreadAttributes,
  148. Int32 ImpersonationLevel,
  149. Int32 dwTokenType,
  150. ref IntPtr phNewToken);
  151.  
  152. [DllImport("wtsapi32.dll", SetLastError = true)]
  153. public static extern bool WTSQueryUserToken(
  154. Int32 sessionId,
  155. out IntPtr Token);
  156.  
  157. [DllImport("userenv.dll", SetLastError = true)]
  158. static extern bool CreateEnvironmentBlock(
  159. out IntPtr lpEnvironment,
  160. IntPtr hToken,
  161. bool bInherit);
  162.  
  163. public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
  164. public static void ShowMessageBox(string message, string title)
  165. {
  166. int resp = ;
  167. WTSSendMessage(
  168. WTS_CURRENT_SERVER_HANDLE,
  169. WTSGetActiveConsoleSessionId(),
  170. title, title.Length,
  171. message, message.Length,
  172. , , out resp, false);
  173. }
  174.  
  175. [DllImport("kernel32.dll", SetLastError = true)]
  176. public static extern int WTSGetActiveConsoleSessionId();
  177.  
  178. [DllImport("wtsapi32.dll", SetLastError = true)]
  179. public static extern bool WTSSendMessage(
  180. IntPtr hServer,
  181. int SessionId,
  182. String pTitle,
  183. int TitleLength,
  184. String pMessage,
  185. int MessageLength,
  186. int Style,
  187. int Timeout,
  188. out int pResponse,
  189. bool bWait);
  190. }
  • 第三种方法(可以远程)

调用方法

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

代码类

  1. /// <summary>
  2. /// 解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离
  3. /// 用于windows服务 启动外部程序 或者截取图片等
  4. /// 默认windows服务的权限是在session0中
  5. /// </summary>
  6. public class SessionUtility
  7. {
  8. #region 如果服务只是简单的向桌面用户Session 发送消息窗口,则可以使用WTSSendMessage 函数实现
  9.  
  10. public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
  11.  
  12. public static void ShowMessageBox(string message, string title)
  13. {
  14. int resp = ;
  15. WTSSendMessage(
  16. WTS_CURRENT_SERVER_HANDLE,
  17. WTSGetActiveConsoleSessionId(),
  18. title, title.Length,
  19. message, message.Length,
  20. , , out resp, false);
  21. }
  22.  
  23. [DllImport("kernel32.dll", SetLastError = true)]
  24. public static extern int WTSGetActiveConsoleSessionId();
  25.  
  26. [DllImport("wtsapi32.dll", SetLastError = true)]
  27. public static extern bool WTSSendMessage(
  28. IntPtr hServer,
  29. int SessionId,
  30. String pTitle,
  31. int TitleLength,
  32. String pMessage,
  33. int MessageLength,
  34. int Style,
  35. int Timeout,
  36. out int pResponse,
  37. bool bWait);
  38.  
  39. //在ShowMessageBox 函数中调用了WTSSendMessage 来发送信息窗口,这样我们就可以在Service 的OnStart 函数中使用,打开Service1.cs 加入下面代码:
  40. //protected override void OnStart(string[] args)
  41. //{
  42. // Interop.ShowMessageBox("This a message from AlertService.",
  43. // "AlertService Message");
  44. //}
  45.  
  46. #endregion
  47.  
  48. /*
  49. * 如果想通过服务向桌面用户Session 创建一个复杂UI 程序界面,
  50. * 则需要使用CreateProcessAsUser 函数为用户创建一个新进程用来运行相应的程序。
  51. */
  52.  
  53. #region 复杂进程
  54.  
  55. public static void CreateProcess(string app, string para, int sessionID)
  56. {
  57. if (!string.IsNullOrEmpty(para))
  58. {
  59. para = app + @"\" + para;
  60. app = null;
  61. }
  62. bool result;
  63. IntPtr hToken = WindowsIdentity.GetCurrent().Token;
  64. IntPtr hDupedToken = IntPtr.Zero;
  65.  
  66. var pi = new PROCESS_INFORMATION();
  67. var sa = new SECURITY_ATTRIBUTES();
  68. sa.Length = Marshal.SizeOf(sa);
  69.  
  70. var si = new STARTUPINFO();
  71. si.cb = Marshal.SizeOf(si);
  72.  
  73. int dwSessionID = sessionID;
  74. if (sessionID < )
  75. dwSessionID = WTSGetActiveConsoleSessionId();
  76. result = WTSQueryUserToken(dwSessionID, out hToken);
  77.  
  78. if (!result)
  79. {
  80. ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
  81. }
  82.  
  83. result = DuplicateTokenEx(
  84. hToken,
  85. GENERIC_ALL_ACCESS,
  86. ref sa,
  87. (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
  88. (int)TOKEN_TYPE.TokenPrimary,
  89. ref hDupedToken
  90. );
  91.  
  92. if (!result)
  93. {
  94. ShowMessageBox("DuplicateTokenEx failed", "AlertService Message");
  95. }
  96.  
  97. IntPtr lpEnvironment = IntPtr.Zero;
  98. result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
  99.  
  100. if (!result)
  101. {
  102. ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
  103. }
  104.  
  105. result = CreateProcessAsUser(
  106. hDupedToken,
  107. app,
  108. para,
  109. ref sa, ref sa,
  110. false, , IntPtr.Zero,
  111. null, ref si, ref pi);
  112.  
  113. if (!result)
  114. {
  115. int error = Marshal.GetLastWin32Error();
  116. string message = String.Format("CreateProcessAsUser Error: {0}", error);
  117. ShowMessageBox(message, "AlertService Message");
  118. }
  119.  
  120. if (pi.hProcess != IntPtr.Zero)
  121. CloseHandle(pi.hProcess);
  122. if (pi.hThread != IntPtr.Zero)
  123. CloseHandle(pi.hThread);
  124. if (hDupedToken != IntPtr.Zero)
  125. CloseHandle(hDupedToken);
  126. }
  127.  
  128. [StructLayout(LayoutKind.Sequential)]
  129. public struct STARTUPINFO
  130. {
  131. public Int32 cb;
  132. public string lpReserved;
  133. public string lpDesktop;
  134. public string lpTitle;
  135. public Int32 dwX;
  136. public Int32 dwY;
  137. public Int32 dwXSize;
  138. public Int32 dwXCountChars;
  139. public Int32 dwYCountChars;
  140. public Int32 dwFillAttribute;
  141. public Int32 dwFlags;
  142. public Int16 wShowWindow;
  143. public Int16 cbReserved2;
  144. public IntPtr lpReserved2;
  145. public IntPtr hStdInput;
  146. public IntPtr hStdOutput;
  147. public IntPtr hStdError;
  148. }
  149.  
  150. [StructLayout(LayoutKind.Sequential)]
  151. public struct PROCESS_INFORMATION
  152. {
  153. public IntPtr hProcess;
  154. public IntPtr hThread;
  155. public Int32 dwProcessID;
  156. public Int32 dwThreadID;
  157. }
  158.  
  159. [StructLayout(LayoutKind.Sequential)]
  160. public struct SECURITY_ATTRIBUTES
  161. {
  162. public Int32 Length;
  163. public IntPtr lpSecurityDescriptor;
  164. public bool bInheritHandle;
  165. }
  166.  
  167. public enum SECURITY_IMPERSONATION_LEVEL
  168. {
  169. SecurityAnonymous,
  170. SecurityIdentification,
  171. SecurityImpersonation,
  172. SecurityDelegation
  173. }
  174.  
  175. public enum TOKEN_TYPE
  176. {
  177. TokenPrimary = ,
  178. TokenImpersonation
  179. }
  180.  
  181. public const int GENERIC_ALL_ACCESS = 0x10000000;
  182.  
  183. [DllImport("kernel32.dll", SetLastError = true,
  184. CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  185. public static extern bool CloseHandle(IntPtr handle);
  186.  
  187. [DllImport("advapi32.dll", SetLastError = true,
  188. CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  189. public static extern bool CreateProcessAsUser(
  190. IntPtr hToken,
  191. string lpApplicationName,
  192. string lpCommandLine,
  193. ref SECURITY_ATTRIBUTES lpProcessAttributes,
  194. ref SECURITY_ATTRIBUTES lpThreadAttributes,
  195. bool bInheritHandle,
  196. Int32 dwCreationFlags,
  197. IntPtr lpEnvrionment,
  198. string lpCurrentDirectory,
  199. ref STARTUPINFO lpStartupInfo,
  200. ref PROCESS_INFORMATION lpProcessInformation);
  201.  
  202. [DllImport("advapi32.dll", SetLastError = true)]
  203. public static extern bool DuplicateTokenEx(
  204. IntPtr hExistingToken,
  205. Int32 dwDesiredAccess,
  206. ref SECURITY_ATTRIBUTES lpThreadAttributes,
  207. Int32 ImpersonationLevel,
  208. Int32 dwTokenType,
  209. ref IntPtr phNewToken);
  210.  
  211. [DllImport("wtsapi32.dll", SetLastError = true)]
  212. public static extern bool WTSQueryUserToken(
  213. Int32 sessionId,
  214. out IntPtr Token);
  215.  
  216. [DllImport("userenv.dll", SetLastError = true)]
  217. private static extern bool CreateEnvironmentBlock(
  218. out IntPtr lpEnvironment,
  219. IntPtr hToken,
  220. bool bInherit);
  221.  
  222. #endregion
  223. }
  • 第四种方法

调用方法

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

代码类

  1. /// <summary>
  2. /// Class that allows running applications with full admin rights. In
  3. /// addition the application launched will bypass the Vista UAC prompt.
  4. /// </summary>
  5. public class ApplicationLoader
  6. {
  7.  
  8. #region Structrures
  9.  
  10. [StructLayout(LayoutKind.Sequential)]
  11. public struct SECURITY_ATTRIBUTES
  12. {
  13. public int Length;
  14. public IntPtr lpSecurityDescriptor;
  15. public bool bInheritHandle;
  16. }
  17.  
  18. [StructLayout(LayoutKind.Sequential)]
  19. public struct STARTUPINFO
  20. {
  21. public int cb;
  22. public String lpReserved;
  23. public String lpDesktop;
  24. public String lpTitle;
  25. public uint dwX;
  26. public uint dwY;
  27. public uint dwXSize;
  28. public uint dwYSize;
  29. public uint dwXCountChars;
  30. public uint dwYCountChars;
  31. public uint dwFillAttribute;
  32. public uint dwFlags;
  33. public short wShowWindow;
  34. public short cbReserved2;
  35. public IntPtr lpReserved2;
  36. public IntPtr hStdInput;
  37. public IntPtr hStdOutput;
  38. public IntPtr hStdError;
  39.  
  40. }
  41.  
  42. [StructLayout(LayoutKind.Sequential)]
  43. public struct PROCESS_INFORMATION
  44. {
  45. public IntPtr hProcess;
  46. public IntPtr hThread;
  47. public uint dwProcessId;
  48. public uint dwThreadId;
  49. }
  50.  
  51. #endregion
  52.  
  53. #region Enumberation
  54. enum TOKEN_TYPE : int
  55. {
  56. TokenPrimary = ,
  57. TokenImpersonation =
  58. }
  59.  
  60. enum SECURITY_IMPERSONATION_LEVEL : int
  61. {
  62. SecurityAnonymous = ,
  63. SecurityIdentification = ,
  64. SecurityImpersonation = ,
  65. SecurityDelegation = ,
  66. }
  67.  
  68. #endregion
  69.  
  70. #region Constants
  71.  
  72. public const int TOKEN_DUPLICATE = 0x0002;
  73. public const uint MAXIMUM_ALLOWED = 0x2000000;
  74. public const int CREATE_NEW_CONSOLE = 0x00000010;
  75.  
  76. public const int IDLE_PRIORITY_CLASS = 0x40;
  77. public const int NORMAL_PRIORITY_CLASS = 0x20;
  78. public const int HIGH_PRIORITY_CLASS = 0x80;
  79. public const int REALTIME_PRIORITY_CLASS = 0x100;
  80.  
  81. #endregion
  82.  
  83. #region Win32 API Imports
  84.  
  85. [DllImport("kernel32.dll", SetLastError = true)]
  86. private static extern bool CloseHandle(IntPtr hSnapshot);
  87.  
  88. [DllImport("kernel32.dll")]
  89. static extern uint WTSGetActiveConsoleSessionId();
  90.  
  91. [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  92. public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
  93. ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
  94. String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
  95.  
  96. [DllImport("kernel32.dll")]
  97. static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);
  98.  
  99. [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
  100. public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
  101. ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
  102. int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
  103.  
  104. [DllImport("kernel32.dll")]
  105. static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
  106.  
  107. [DllImport("advapi32.dll", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
  108. static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
  109.  
  110. //[DllImport("advapi32.dll", SetLastError = true)]
  111. //[return: MarshalAs(UnmanagedType.Bool)]
  112. //static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, ref IntPtr TokenHandle);
  113.  
  114. #endregion
  115.  
  116. /// <summary>
  117. /// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
  118. /// </summary>
  119. /// <param name="applicationName">The name of the application to launch</param>
  120. /// <param name="procInfo">Process information regarding the launched application that gets returned to the caller</param>
  121. /// <returns></returns>
  122. public static bool StartProcessAndBypassUAC(String applicationName, out PROCESS_INFORMATION procInfo)
  123. {
  124. uint winlogonPid = ;
  125. IntPtr hUserTokenDup = IntPtr.Zero,
  126. hPToken = IntPtr.Zero,
  127. hProcess = IntPtr.Zero;
  128. procInfo = new PROCESS_INFORMATION();
  129.  
  130. // obtain the currently active session id; every logged on user in the system has a unique session id
  131. TSControl.WTS_SESSION_INFO[] pSessionInfo = TSControl.SessionEnumeration();
  132. uint dwSessionId = ;
  133. for (int i = ; i < pSessionInfo.Length; i++)
  134. {
  135. if (pSessionInfo[i].SessionID != )
  136. {
  137. try
  138. {
  139. int count = ;
  140. IntPtr buffer = IntPtr.Zero;
  141. StringBuilder sb = new StringBuilder();
  142.  
  143. bool bsuccess = TSControl.WTSQuerySessionInformation(
  144. IntPtr.Zero, pSessionInfo[i].SessionID,
  145. TSControl.WTSInfoClass.WTSUserName, out sb, out count);
  146.  
  147. if (bsuccess)
  148. {
  149. if (sb.ToString().Trim() == "Administrator")//Administrator
  150. {
  151. dwSessionId = (uint)pSessionInfo[i].SessionID;
  152. }
  153. }
  154. }
  155. catch (Exception ex)
  156. {
  157. //LoaderService.WriteLog(ex.Message.ToString(), "Monitor");
  158. }
  159. }
  160. }
  161.  
  162. // obtain the process id of the winlogon process that is running within the currently active session
  163. Process[] processes = Process.GetProcessesByName("explorer");
  164. foreach (Process p in processes)
  165. {
  166. if ((uint)p.SessionId == dwSessionId)
  167. {
  168. winlogonPid = (uint)p.Id;
  169. }
  170. }
  171.  
  172. //LoaderService.WriteLog(winlogonPid.ToString(), "Monitor");
  173.  
  174. // obtain a handle to the winlogon process
  175. hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
  176.  
  177. // obtain a handle to the access token of the winlogon process
  178. if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
  179. {
  180. CloseHandle(hProcess);
  181. return false;
  182. }
  183.  
  184. // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
  185. // I would prefer to not have to use a security attribute variable and to just
  186. // simply pass null and inherit (by default) the security attributes
  187. // of the existing token. However, in C# structures are value types and therefore
  188. // cannot be assigned the null value.
  189. SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
  190. sa.Length = Marshal.SizeOf(sa);
  191.  
  192. // copy the access token of the winlogon process; the newly created token will be a primary token
  193. if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
  194. {
  195. CloseHandle(hProcess);
  196. CloseHandle(hPToken);
  197. return false;
  198. }
  199.  
  200. // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
  201. // the window station has a desktop that is invisible and the process is incapable of receiving
  202. // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
  203. // interaction with the new process.
  204. STARTUPINFO si = new STARTUPINFO();
  205. si.cb = (int)Marshal.SizeOf(si);
  206. si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
  207.  
  208. // flags that specify the priority and creation method of the process
  209. int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
  210.  
  211. // create a new process in the current user's logon session
  212. bool result = CreateProcessAsUser(hUserTokenDup, // client's access token
  213. null, // file to execute
  214. applicationName, // command line
  215. ref sa, // pointer to process SECURITY_ATTRIBUTES
  216. ref sa, // pointer to thread SECURITY_ATTRIBUTES
  217. false, // handles are not inheritable
  218. dwCreationFlags, // creation flags
  219. IntPtr.Zero, // pointer to new environment block
  220. null, // name of current directory
  221. ref si, // pointer to STARTUPINFO structure
  222. out procInfo // receives information about new process
  223. );
  224.  
  225. // invalidate the handles
  226. CloseHandle(hProcess);
  227. CloseHandle(hPToken);
  228. CloseHandle(hUserTokenDup);
  229. //LoaderService.WriteLog("launch Task", "Monitor");
  230.  
  231. return result; // return the result
  232. }
  233.  
  234. }
  1. public class TSControl
  2. {
  3. /**/
  4. /// <summary>
  5. /// Terminal Services API Functions,The WTSEnumerateSessions function retrieves a list of sessions on a specified terminal server,
  6. /// </summary>
  7. /// <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>
  8. /// <param name="Reserved">Reserved; must be zero</param>
  9. /// <param name="Version">[in] Specifies the version of the enumeration request. Must be 1. </param>
  10. /// <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.
  11. /// To be able to enumerate a session, you need to have the Query Information permission.</param>
  12. /// <param name="pCount">[out] Pointer to the variable that receives the number of WTS_SESSION_INFO structures returned in the ppSessionInfo buffer. </param>
  13. /// <returns>If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero</returns>
  14. [DllImport("wtsapi32", CharSet = CharSet.Auto, SetLastError = true)]
  15. private static extern bool WTSEnumerateSessions(int hServer, int Reserved, int Version, ref long ppSessionInfo, ref int pCount);
  16.  
  17. /**/
  18. /// <summary>
  19. /// Terminal Services API Functions,The WTSFreeMemory function frees memory allocated by a Terminal Services function.
  20. /// </summary>
  21. /// <param name="pMemory">[in] Pointer to the memory to free</param>
  22. [DllImport("wtsapi32.dll")]
  23. public static extern void WTSFreeMemory(System.IntPtr pMemory);
  24.  
  25. /**/
  26. /// <summary>
  27. /// Terminal Services API Functions,The WTSLogoffSession function logs off a specified Terminal Services session.
  28. /// </summary>
  29. /// <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>
  30. /// <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.
  31. /// To be able to log off another user's session, you need to have the Reset permission </param>
  32. /// <param name="bWait">[in] Indicates whether the operation is synchronous.
  33. /// If bWait is TRUE, the function returns when the session is logged off.
  34. /// If bWait is FALSE, the function returns immediately.</param>
  35. /// <returns>If the function succeeds, the return value is a nonzero value.
  36. /// If the function fails, the return value is zero.</returns>
  37. [DllImport("wtsapi32.dll")]
  38. public static extern bool WTSLogoffSession(int hServer, long SessionId, bool bWait);
  39.  
  40. [DllImport("Wtsapi32.dll")]
  41. public static extern bool WTSQuerySessionInformation(
  42. System.IntPtr hServer,
  43. int sessionId,
  44. WTSInfoClass wtsInfoClass,
  45. out StringBuilder ppBuffer,
  46. out int pBytesReturned
  47. );
  48.  
  49. public enum WTSInfoClass
  50. {
  51. WTSInitialProgram,
  52. WTSApplicationName,
  53. WTSWorkingDirectory,
  54. WTSOEMId,
  55. WTSSessionId,
  56. WTSUserName,
  57. WTSWinStationName,
  58. WTSDomainName,
  59. WTSConnectState,
  60. WTSClientBuildNumber,
  61. WTSClientName,
  62. WTSClientDirectory,
  63. WTSClientProductId,
  64. WTSClientHardwareId,
  65. WTSClientAddress,
  66. WTSClientDisplay,
  67. WTSClientProtocolType
  68. }
  69.  
  70. /**/
  71. /// <summary>
  72. /// The WTS_CONNECTSTATE_CLASS enumeration type contains INT values that indicate the connection state of a Terminal Services session.
  73. /// </summary>
  74. public enum WTS_CONNECTSTATE_CLASS
  75. {
  76. WTSActive,
  77. WTSConnected,
  78. WTSConnectQuery,
  79. WTSShadow,
  80. WTSDisconnected,
  81. WTSIdle,
  82. WTSListen,
  83. WTSReset,
  84. WTSDown,
  85. WTSInit,
  86. }
  87.  
  88. /**/
  89. /// <summary>
  90. /// The WTS_SESSION_INFO structure contains information about a client session on a terminal server.
  91. /// if the WTS_SESSION_INFO.SessionID==0, it means that the SESSION is the local logon user's session.
  92. /// </summary>
  93. public struct WTS_SESSION_INFO
  94. {
  95. public int SessionID;
  96. [MarshalAs(UnmanagedType.LPTStr)]
  97. public string pWinStationName;
  98. public WTS_CONNECTSTATE_CLASS state;
  99. }
  100.  
  101. /**/
  102. /// <summary>
  103. /// The SessionEnumeration function retrieves a list of
  104. ///WTS_SESSION_INFO on a current terminal server.
  105. /// </summary>
  106. /// <returns>a list of WTS_SESSION_INFO on a current terminal server</returns>
  107. public static WTS_SESSION_INFO[] SessionEnumeration()
  108. {
  109. //Set handle of terminal server as the current terminal server
  110. int hServer = ;
  111. bool RetVal;
  112. long lpBuffer = ;
  113. int Count = ;
  114. long p;
  115. WTS_SESSION_INFO Session_Info = new WTS_SESSION_INFO();
  116. WTS_SESSION_INFO[] arrSessionInfo;
  117. RetVal = WTSEnumerateSessions(hServer, , , ref lpBuffer, ref Count);
  118. arrSessionInfo = new WTS_SESSION_INFO[];
  119. if (RetVal)
  120. {
  121. arrSessionInfo = new WTS_SESSION_INFO[Count];
  122. int i;
  123. p = lpBuffer;
  124. for (i = ; i < Count; i++)
  125. {
  126. arrSessionInfo[i] =
  127. (WTS_SESSION_INFO)Marshal.PtrToStructure(new IntPtr(p),
  128. Session_Info.GetType());
  129. p += Marshal.SizeOf(Session_Info.GetType());
  130. }
  131. WTSFreeMemory(new IntPtr(lpBuffer));
  132. }
  133. else
  134. {
  135. //Insert Error Reaction Here
  136. }
  137. return arrSessionInfo;
  138. }
  139.  
  140. public TSControl()
  141. {
  142. //
  143. // TODO: 在此处添加构造函数逻辑
  144. //
  145.  
  146. }
  147.  
  148. }
  • 参考资料

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交互程序的更多相关文章

  1. windows服务启动有界面的程序

    大家写windows服务守护进程的时候,肯定会遇到启动的程序看不到界面,只能在任务管理器里面看到xxx.exe问题. 发现可能有如下情况 a.无论是开机,还是程序被关掉后,守护服务启动的程序只能看到任 ...

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

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

  3. MongoDB做为一项windows服务启动

    MongoDB做为一项windows服务启动 Windows版本安装 MongoDB的官方下载站是http://www.mongodb.org/downloads,可以去上面下载最新的对应版本,有32 ...

  4. 玩转Windows服务系列——无COM接口Windows服务启动失败原因及解决方案

    将VS创建的Windows服务项目编译生成的程序,通过命令行 “服务.exe -Service”注册为Windows服务后,就可以通过服务管理器进行管理了. 问题 通过服务管理器进行启动的时候,发现服 ...

  5. 玩转Windows服务系列——Windows服务启动超时时间

    最近有客户反映,机房出现断电情况,服务器的系统重新启动后,数据库服务自启动失败.第一次遇到这种情况,为了查看是不是断电情况导致数据库文件损坏,从客户的服务器拿到数据库的日志,进行分析. 数据库工作机制 ...

  6. C#判断程序是由Windows服务启动还是用户启动

    在Windows系统做网络开发,很多时候都是使用Windows服务的模式,但在调度阶段,我们更多的是使用控制台的模式.在开发程序的时候,我们在Program的Main入口进行判断.最初开始使用Envi ...

  7. windows服务启动 1053错误

    1.问题描述 今天在启动一个Windows服务时,服务启动不了,且提示:1053错误 那么是什么导致了1053错误呢? 2.他山之石 百度了一下,发现有人作出下面的解释并给出了解决方法: “常常是因为 ...

  8. Redis Windows 服务启动异常 错误码1067

    https://blog.csdn.net/after_you/article/details/62215163 Redis Windows 服务启动异常 错误码1067 下载了Redis 2.8.2 ...

  9. C# windows服务,解决应用程序开机自启问题

    最近在东营做一个超市购物的项目,业务体量很小,是仅供内部员工使用的内网应用程序,其中涉及一个商品数据同步的winform应用程序,有一个问题就是服务器重启后,必须登录服务器操作系统,手动启动才行,于是 ...

随机推荐

  1. 排序矩阵中的从小到大第k个数 · Kth Smallest Number In Sorted Matrix

    [抄题]: 在一个排序矩阵中找从小到大的第 k 个整数. 排序矩阵的定义为:每一行递增,每一列也递增. [思维问题]: 不知道应该怎么加,因为不是一维单调的. [一句话思路]: 周围两个数给x或y挪一 ...

  2. 通过BeanShell获取UUID并将参数传递给Jmeter

    有些HTTPS请求报文的报文体中包含由客户端生成的UUID,在用Jmeter做接口自动化测试的时候,因为越过了客户端,直接向服务器端发送报文,所以,需要在Jmeter中通过beanshell获取UUI ...

  3. 2018.10.16 NOIP模拟 华莱士(并查集)

    传送门 按照题意模拟维护最小的环套树森林就行了. 然而考试的时候naivenaivenaive瞎写了一个错误的贪心. 代码

  4. 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)

    3295: [Cqoi2011]动态逆序对 **Time Limit: 10 Sec Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j& ...

  5. org.eclipse.ui.PartInitException: Unable to open editor, unknown editor ID: org.xmen.ui.text.XMLTextEditor

    无法打开struts模式的编译xml的编译器,然后打开.project文件,编辑最后一行,找到<natures>结点,增加一条<nature>com.genuitec.ecli ...

  6. (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 ...

  7. java基础-day4

    第04天 java基础语法 今日内容介绍 u Random u 数组 第1章   Random 1.1      产生整数随机数 1.1.1    Random的使用步骤 我们想产生1~100(包含1 ...

  8. 『IOS』 遇到问题记录(长期更新)

    遇到的很多问题,解决后都是自己记着,以为不会忘记,之后却会想不起来了. 所以把今后解决的问题记录在这. 一. 在二级页面设置了CAlayer的代理,在返回一级页面报错: EXC_BAD_ACCESS( ...

  9. eclipse快捷键(增加一些4连组合快捷键)

    http://www.blogjava.net/i369/articles/83309.html   ECLISPE的快捷键大全 Eclipse 常用快捷键收集2006年09月29日 星期五 12:0 ...

  10. svn服务器快速搭建及简单配置

    http://www.360doc.com/content/11/0711/19/5131531_132950891.shtml 简介Svn已经不容质疑的成为了一款流行的代码控制工具,但是你是否还在为 ...