asp.net中穿透Session 0 隔离(二)
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)
{
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 系统中服务与桌面用户的交互操作。
参考资料
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_jb51.rar
作者:李敬然(Gnie)
出处:{GnieTech} (http://www.cnblogs.com/gnielee/)
相关文章
PHP session_start()很慢问题分析与解决办法
本文章来给各位同学介绍一下关于PHP session_start()很慢问题分析与解决办法,希望碰到此问题的同学可进入参考。 最近在做东西的时候发现一个问题 有一个接口挂...2016-11-25PHP分布式框架如何使用Memcache同步SESSION教程
本教程主要讲解PHP项目如何用实现memcache分布式,配置使用memcache存储session数据,以及memcache的SESSION数据如何同步。 至于Memcache的安装配置,我们就不讲了,以前...2016-11-25- 这篇文章主要介绍了C#中的session用法 ,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-25
Python3使用Selenium获取session和token方法详解
这篇文章主要介绍了Python3使用Selenium获取session和token方法详解,需要的朋友可以参考下...2021-02-17- session和cookie是网站浏览中较为常见的两个概念,也是比较难以辨析的两个概念,但它们在点击流及基于用户浏览行为的网站分析中却相当关键。基于网上一些文章和资料的参阅,及作者个人的应用体会,对这两个概念做一个简单的阐述...2013-09-11
- 这篇文章主要介绍了Vue项目移动端滚动穿透问题的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-05-20
- session在php中是一个非常重要的东西,像我们用户登录一般都使用到session这个东西,相对于cookie来说session 要安全很多,同时我们购物车经常使用session来做临时的记录保存哦。使用session保存页面登录信息1、数据库连接...2015-10-21
- 这篇文章主要介绍了Vue使用axios引起的后台session不同操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-14
- PHP的session功能,一直为许多的初学者为难。就连有些老手,有时都被搞得莫名其妙。本文,将这些问题,做一个简单的汇总,以便大家查阅。 1. 错误提示 引用 代...2016-11-25
- 要设置php生存有效时间我们可以利用session_set_cookie_params函数或修改php.ini文件哦,下面小编来介绍一下。 第一种方法:session_set_cookie_params 函数原型 voi...2016-11-25
jQuery ajax全局函数处理session过期后的ajax跳转问题
这篇文章主要介绍了基于jQuery的全局ajax函数处理session过期后的ajax操作的相关资料,需要的朋友可以参考下...2016-06-12jsp使用sessionScope获取session案例详解
这篇文章主要介绍了jsp使用sessionScope获取session案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-29- 本文主要介绍了Electron点击穿透不规则窗体的透明区域的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-21
- 这篇文章主要介绍了C#实现简单获取及设置Session类,涉及C#针对session的设置及获取的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 上一篇我们已经对Session 0 隔离有了进一步认识,如果在开发过程中确实需要服务与桌面用户进行交互,可以通过远程桌面服务的API 绕过Session 0 的隔离完成交互操作...2021-09-22
- 下面小编就为大家带来一篇Node.js刷新session过期时间的实现方法推荐。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-05-20
- 关于PHP session并发及session读写锁问题估计各大程序员都不会想到这个问题,因为一般情况我们不会使用session来做并发操作了,但有时也有可能用到,下面整理一个session并...2016-11-25
Nodejs中session的简单使用及通过session实现身份验证的方法
session的本质使用cookie来实现。本文给大家介绍Nodejs中session的简单使用及通过session实现身份验证的方法,对node.js session相关知识感兴趣的朋友一起学习吧...2016-02-09- Session和Cookie的使用在php中非常常见的了,我们通常用于登录双验证了,下文小编为各位介绍利用Session和Cookie来做一些像用户登录验证、记录用户浏览历史,存储购物车数...2016-11-25
- php中session经常会出现一些很奇怪的问题,这些问题很多都是小细节的事情,对于php 初学者来说可能很难发现是什么原因,今天我们把几乎所有的session引起或出现的问题收集...2016-11-25