找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 5419|回复: 0

穿透Session 0 隔离(二)

[复制链接]
发表于 2012-4-19 14:06:39 | 显示全部楼层 |阅读模式
上一篇 我们已经对Session 0 隔离有了进一步认识,如果在开发过程中确实需要服务与桌面用户进行交互,可以通过远程桌面服务的API 绕过Session 0 的隔离完成交互操作。
     对于简单的交互,服务可以通过WTSSendMessage 函数,在用户Session 上显示消息窗口。对于一些复杂的UI 交互,必须调用CreateProcessAsUser 或其他方法(WCF、.NET远程处理等)进行跨Session 通信,在桌面用户上创建一个应用程序界面。
WTSSendMessage 函数
     如果服务只是简单的向桌面用户Session 发送消息窗口,则可以使用WTSSendMessage 函数实现。首先,在上一篇下载的代码中加入一个Interop.cs 类,并在类中加入如下代码:
  1. public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
  2. public static void ShowMessageBox(string message, string title)
  3. {
  4.     int resp = 0;
  5.     WTSSendMessage(
  6.         WTS_CURRENT_SERVER_HANDLE,
  7.         WTSGetActiveConsoleSessionId(),
  8.         title, title.Length,
  9.         message, message.Length,
  10.         0, 0, out resp, false);
  11. }
  12. [DllImport("kernel32.dll", SetLastError = true)]
  13. public static extern int WTSGetActiveConsoleSessionId();
  14. [DllImport("wtsapi32.dll", SetLastError = true)]
  15. public static extern bool WTSSendMessage(
  16.     IntPtr hServer,
  17.     int SessionId,
  18.     String pTitle,
  19.     int TitleLength,
  20.     String pMessage,
  21.     int MessageLength,
  22.     int Style,
  23.     int Timeout,
  24.     out int pResponse,
  25.     bool bWait);
复制代码
     在ShowMessageBox 函数中调用了WTSSendMessage 来发送信息窗口,这样我们就可以在Service 的OnStart 函数中使用,打开Service1.cs 加入下面代码:
  1. protected override void OnStart(string[] args)
  2. {
  3.     Interop.ShowMessageBox("This a message from AlertService.",
  4.                            "AlertService Message");
  5. }
复制代码
     编译程序后在服务管理器中重新启动AlertService 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是Session 0 中。
CreateProcessAsUser 函数
     如果想通过服务向桌面用户Session 创建一个复杂UI 程序界面,则需要使用CreateProcessAsUser 函数为用户创建一个新进程用来运行相应的程序。打开Interop 类继续添加下面代码:
  1. public static void CreateProcess(string app, string path)
  2. {
  3.     bool result;
  4.     IntPtr hToken = WindowsIdentity.GetCurrent().Token;
  5.     IntPtr hDupedToken = IntPtr.Zero;
  6.     PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
  7.     SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
  8.     sa.Length = Marshal.SizeOf(sa);
  9.     STARTUPINFO si = new STARTUPINFO();
  10.     si.cb = Marshal.SizeOf(si);
  11.     int dwSessionID = WTSGetActiveConsoleSessionId();
  12.     result = WTSQueryUserToken(dwSessionID, out hToken);
  13.    
  14.     if (!result)
  15.     {
  16.         ShowMessageBox("WTSQueryUserToken failed", "AlertService Message");
  17.     }
  18.     result = DuplicateTokenEx(
  19.           hToken,
  20.           GENERIC_ALL_ACCESS,
  21.           ref sa,
  22.           (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
  23.           (int)TOKEN_TYPE.TokenPrimary,
  24.           ref hDupedToken
  25.        );
  26.     if (!result)
  27.     {
  28.         ShowMessageBox("DuplicateTokenEx failed" ,"AlertService Message");
  29.     }
  30.     IntPtr lpEnvironment = IntPtr.Zero;
  31.     result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
  32.     if (!result)
  33.     {
  34.         ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
  35.     }
  36.     result = CreateProcessAsUser(
  37.                          hDupedToken,
  38.                          app,
  39.                          String.Empty,
  40.                          ref sa, ref sa,
  41.                          false, 0, IntPtr.Zero,
  42.                          path, ref si, ref pi);
  43.     if (!result)
  44.     {
  45.         int error = Marshal.GetLastWin32Error();
  46.         string message = String.Format("CreateProcessAsUser Error: {0}", error);
  47.         ShowMessageBox(message, "AlertService Message");
  48.     }
  49.     if (pi.hProcess != IntPtr.Zero)
  50.         CloseHandle(pi.hProcess);
  51.     if (pi.hThread != IntPtr.Zero)
  52.         CloseHandle(pi.hThread);
  53.     if (hDupedToken != IntPtr.Zero)
  54.         CloseHandle(hDupedToken);
  55. }
  56. [StructLayout(LayoutKind.Sequential)]
  57. public struct STARTUPINFO
  58. {
  59.     public Int32 cb;
  60.     public string lpReserved;
  61.     public string lpDesktop;
  62.     public string lpTitle;
  63.     public Int32 dwX;
  64.     public Int32 dwY;
  65.     public Int32 dwXSize;
  66.     public Int32 dwXCountChars;
  67.     public Int32 dwYCountChars;
  68.     public Int32 dwFillAttribute;
  69.     public Int32 dwFlags;
  70.     public Int16 wShowWindow;
  71.     public Int16 cbReserved2;
  72.     public IntPtr lpReserved2;
  73.     public IntPtr hStdInput;
  74.     public IntPtr hStdOutput;
  75.     public IntPtr hStdError;
  76. }
  77. [StructLayout(LayoutKind.Sequential)]
  78. public struct PROCESS_INFORMATION
  79. {
  80.     public IntPtr hProcess;
  81.     public IntPtr hThread;
  82.     public Int32 dwProcessID;
  83.     public Int32 dwThreadID;
  84. }
  85. [StructLayout(LayoutKind.Sequential)]
  86. public struct SECURITY_ATTRIBUTES
  87. {
  88.     public Int32 Length;
  89.     public IntPtr lpSecurityDescriptor;
  90.     public bool bInheritHandle;
  91. }
  92. public enum SECURITY_IMPERSONATION_LEVEL
  93. {
  94.     SecurityAnonymous,
  95.     SecurityIdentification,
  96.     SecurityImpersonation,
  97.     SecurityDelegation
  98. }
  99. public enum TOKEN_TYPE
  100. {
  101.     TokenPrimary = 1,
  102.     TokenImpersonation
  103. }
  104. public const int GENERIC_ALL_ACCESS = 0x10000000;
  105. [DllImport("kernel32.dll", SetLastError = true,
  106.     CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  107. public static extern bool CloseHandle(IntPtr handle);
  108. [DllImport("advapi32.dll", SetLastError = true,
  109.     CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
  110. public static extern bool CreateProcessAsUser(
  111.     IntPtr hToken,
  112.     string lpApplicationName,
  113.     string lpCommandLine,
  114.     ref SECURITY_ATTRIBUTES lpProcessAttributes,
  115.     ref SECURITY_ATTRIBUTES lpThreadAttributes,
  116.     bool bInheritHandle,
  117.     Int32 dwCreationFlags,
  118.     IntPtr lpEnvrionment,
  119.     string lpCurrentDirectory,
  120.     ref STARTUPINFO lpStartupInfo,
  121.     ref PROCESS_INFORMATION lpProcessInformation);
  122. [DllImport("advapi32.dll", SetLastError = true)]
  123. public static extern bool DuplicateTokenEx(
  124.     IntPtr hExistingToken,
  125.     Int32 dwDesiredAccess,
  126.     ref SECURITY_ATTRIBUTES lpThreadAttributes,
  127.     Int32 ImpersonationLevel,
  128.     Int32 dwTokenType,
  129.     ref IntPtr phNewToken);
  130. [DllImport("wtsapi32.dll", SetLastError=true)]
  131. public static extern bool WTSQueryUserToken(
  132.     Int32 sessionId,
  133.     out IntPtr Token);
  134. [DllImport("userenv.dll", SetLastError = true)]
  135. static extern bool CreateEnvironmentBlock(
  136.     out IntPtr lpEnvironment,
  137.     IntPtr hToken,
  138.     bool bInherit);
复制代码
     在CreateProcess 函数中同时也涉及到DuplicateTokenEx、WTSQueryUserToken、CreateEnvironmentBlock 函数的使用,有兴趣的朋友可通过MSDN 进行学习。完成CreateProcess 函数创建后,就可以真正的通过它来调用应用程序了,回到Service1.cs 修改一下OnStart 我们来打开一个CMD 窗口。如下代码:
  1. protected override void OnStart(string[] args)
  2. {
  3.     Interop.CreateProcess("cmd.exe",@"C:\Windows\System32");
  4. }
复制代码
     重新编译程序,启动AlertService 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对Session 0 隔离问题进行解决。大家也可以通过WCF 等技术完成一些更复杂的跨Session 通信方式,实现在Windows 7 及Vista 系统中服务与桌面用户的交互操作。
参考资料
代码下载:

作者:李敬然(Gnie)
出处:{GnieTech}http://www.cnblogs.com/gnielee/
版权声明:本文的版权归作者与博客园共有。转载时须注明本文的详细链接,否则作者将保留追究其法律责任。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?用户注册

×
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-5-6 19:11 , Processed in 0.014349 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表