• 穿透Session 0 隔离(二)


    原地址:http://www.cnblogs.com/gnielee/archive/2010/04/08/1707169.html

         上一篇我们已经对Session 0 隔离有了进一步认识,如果在开发过程中确实需要服务与桌面用户进行交互,可以通过远程桌面服务的API 绕过Session 0 的隔离完成交互操作。

         对于简单的交互,服务可以通过WTSSendMessage 函数,在用户Session 上显示消息窗口。对于一些复杂的UI 交互,必须调用CreateProcessAsUser 或其他方法(WCF、.NET远程处理等)进行跨Session 通信,在桌面用户上创建一个应用程序界面。

    WTSSendMessage 函数

         如果服务只是简单的向桌面用户Session 发送消息窗口,则可以使用WTSSendMessage 函数实现。首先,在上一篇下载的代码中加入一个Interop.cs 类,并在类中加入如下代码:

    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");
    }

         编译程序后在服务管理器中重新启动AlertService 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是Session 0 中。

    CreateProcessAsUser 函数

         如果想通过服务向桌面用户Session 创建一个复杂UI 程序界面,则需要使用CreateProcessAsUser 函数为用户创建一个新进程用来运行相应的程序。打开Interop 类继续添加下面代码:

            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)
                {
                    AutoRun.SetLog("DuplicateTokenEx 失败");
                    //ShowMessageBox("DuplicateTokenEx failed", "AlertService Message");
                }
    
                IntPtr lpEnvironment = IntPtr.Zero;
                result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
    
                if (!result)
                {
                    AutoRun.SetLog("CreateEnvironmentBlock 失败");
                    //ShowMessageBox("CreateEnvironmentBlock failed", "AlertService Message");
                }
    
                result = CreateProcessAsUser(
                                     hDupedToken,
                                     path + app,
                                     String.Empty,
                                     ref sa, ref sa,
                                     false, 0, IntPtr.Zero,
                                     path, ref si, ref pi);
    
                if (!result)
                {
                    int error = Marshal.GetLastWin32Error();
                    string message = String.Format("CreateProcessAsUser Error: {0}", error);
                    AutoRun.SetLog(message);
                    //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);
    
            [DllImport("kernel32.dll")]
            public static extern int WTSGetActiveConsoleSessionId();

         在CreateProcess 函数中同时也涉及到DuplicateTokenEx、WTSQueryUserToken、CreateEnvironmentBlock 函数的使用,有兴趣的朋友可通过MSDN 进行学习。完成CreateProcess 函数创建后,就可以真正的通过它来调用应用程序了,回到Service1.cs 修改一下OnStart 我们来打开一个CMD 窗口。如下代码:

    protected override void OnStart(string[] args)
    {
        Interop.CreateProcess("cmd.exe",@"C:WindowsSystem32");
    }

         重新编译程序,启动AlertService 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对Session 0 隔离问题进行解决。大家也可以通过WCF 等技术完成一些更复杂的跨Session 通信方式,实现在Windows 7 及Vista 系统中服务与桌面用户的交互操作。

    参考资料

    1. WTSSendMessage Function
    http://msdn.microsoft.com/en-us/library/aa383842(VS.85).aspx

    2. CreateProcessAsUser Function
    http://msdn.microsoft.com/en-us/library/ms682429(v=VS.85).aspx

    3. WTSSendMessage (wtsapi32)
    http://www.pinvoke.net/default.aspx/wtsapi32/WTSSendMessage.html

    4. WTSQueryUserToken Function
    http://msdn.microsoft.com/en-us/library/aa383840(VS.85).aspx

    5. http://www.pinvoke.net/

  • 相关阅读:
    TestNG入门教程-6-enabled和priority属性
    TestNG入门教程-5-timeOut属性
    TestNG入门教程-4-Testng中注释简介
    Unicode、UTF-8 和 ISO8859-1到底有什么区别
    java数目
    sql必知必会-总结篇
    mysql监控、性能调优及三范式理解
    loadrunner常用函数总结
    loadrunner监控度量项及中文解释
    linux下crontab的使用实现
  • 原文地址:https://www.cnblogs.com/ful1021/p/4804449.html
Copyright © 2020-2023  润新知