服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服务器之家 - 编程语言 - ASP.NET教程 - asp.net中穿透Session 0 隔离(二)

asp.net中穿透Session 0 隔离(二)

2019-10-10 10:59cnblogs李敬然 ASP.NET教程

上一篇我们已经对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 中。 

asp.net中穿透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) 

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, 
path, 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); 


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

复制代码代码如下:


protected override void OnStart(string[] args) 

Interop.CreateProcess("cmd.exe",@"C:\Windows\System32\"); 


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

 

asp.net中穿透Session 0 隔离(二)

参考资料 

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/

代码下载 AlertService2.rar

作者:李敬然(Gnie) 
出处:{GnieTech} (http://www.cnblogs.com/gnielee/)

延伸 · 阅读

精彩推荐