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

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

2021-11-18 11:57李敬然 C#

服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分。我们可以把服务想像成一种特殊的应用程序,它随系统的“开启~关闭”而“开始~停止”其工作内容,在这期间无需任何用户参与

windows 服务在后台执行着各种各样任务,支持着我们日常的桌面操作。有时候可能需要服务与用户进行信息或界面交互操作,这种方式在xp 时代是没有问题的,但自从vista 开始你会发现这种方式似乎已不起作用。

session 0 隔离实验

下面来做一个名叫alertservice 的服务,它的作用就是向用户发出一个提示对话框,我们看看这个服务在windows 7 中会发生什么情况。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using system.serviceprocess;
using system.windows.forms;
 
namespace alertservice
{
 public partial class service1 : servicebase
 {
  public service1()
  {
   initializecomponent();
  }
 
  protected override void onstart(string[] args)
  {
   messagebox.show("a message from alertservice.");
  }
 
  protected override void onstop()
  {
  }
 }
}

程序编译后通过installutil 将其加载到系统服务中:

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

在服务属性中勾选“allow service to interact with desktop” ,这样可以使alertservice 与桌面用户进行交互。

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

在服务管理器中将alertservice 服务“启动”,这时任务栏中会闪动一个图标:

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

点击该图标会显示下面窗口,提示有个程序(alertservice)正在试图显示信息,是否需要浏览该信息:

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

尝试点击“view the message”,便会显示下图界面(其实这个界面我已经不能从当前桌面操作截图了,是通过virtual pc 截屏的,其原因请继续阅读)。注意观察可以发现下图的桌面背景已经不是windows 7 默认的桌面背景了,说明alertservice 与桌面系统的session 并不相同,这就是session 0 隔离作用的结果。

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

session 0 隔离原理

在windows xp、windows server 2003 或早期windows 系统时代,当第一个用户登录系统后服务和应用程序是在同一个session 中运行的。这就是session 0 如下图所示:

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

 

 

但是这种运行方式提高了系统安全风险,因为服务是通过提升了用户权限运行的,而应用程序往往是那些不具备管理员身份的普通用户运行的,其中的危险显而易见。

从vista 开始session 0 中只包含系统服务,其他应用程序则通过分离的session 运行,将服务与应用程序隔离提高系统的安全性。如下图所示:

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

这样使得session 0 与其他session 之间无法进行交互,不能通过服务向桌面用户弹出信息窗口、ui 窗口等信息。这也就是为什么刚才我说那个图已经不能通过当前桌面进行截图了。

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

session 检查

在实际开发过程中,可以通过process explorer 检查服务或程序处于哪个session,会不会遇到session 0 隔离问题。我们在services 中找到之前加载的alertservice 服务,右键属性查看其session 状态。

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

可看到alertservice 处于session 0 中:

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

再来看看outlook 应用程序:

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

很明显在windows 7 中服务和应用程序是处于不同的session,它们之间加隔了一个保护墙,在下篇文章中将介绍如何穿过这堵保护墙使服务与桌面用户进行交互操作。

 

如果在开发过程中确实需要服务与桌面用户进行交互,可以通过远程桌面服务的api 绕过session 0 的隔离完成交互操作。

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

wtssendmessage 函数

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 加入下面代码:

?
1
2
3
4
5
protected override void onstart(string[] args)
{
 interop.showmessagebox("this a message from alertservice.",
       "alertservice message");
}

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

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

createprocessasuser 函数

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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:windowssystem32");
}


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

 

vista和win7在windows服务中交互桌面权限问题解决方法:穿透Session 0 隔离

延伸 · 阅读

精彩推荐
  • C#C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    C#实现的文件操作封装类完整实例【删除,移动,复制,重命名】

    这篇文章主要介绍了C#实现的文件操作封装类,结合完整实例形式分析了C#封装文件的删除,移动,复制,重命名等操作相关实现技巧,需要的朋友可以参考下...

    Rising_Sun3892021-12-28
  • C#Unity3D UGUI实现缩放循环拖动卡牌展示效果

    Unity3D UGUI实现缩放循环拖动卡牌展示效果

    这篇文章主要为大家详细介绍了Unity3D UGUI实现缩放循环拖动展示卡牌效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参...

    诗远3662022-03-11
  • C#C#基础之泛型

    C#基础之泛型

    泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个新功能。接下来通过本文给大家介绍c#基础之泛型,感兴趣的朋友一起学习吧...

    方小白7732021-12-03
  • C#浅谈C# winForm 窗体闪烁的问题

    浅谈C# winForm 窗体闪烁的问题

    下面小编就为大家带来一篇浅谈C# winForm 窗体闪烁的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    C#教程网7962021-12-21
  • C#c#学习之30分钟学会XAML

    c#学习之30分钟学会XAML

    一个界面程序的核心,无疑就是界面和后台代码,而xaml就是微软为构建应用程序界面而创建的一种描述性语言,也就是说,这东西是搞界面的...

    C#教程网8812021-12-10
  • C#C#直线的最小二乘法线性回归运算实例

    C#直线的最小二乘法线性回归运算实例

    这篇文章主要介绍了C#直线的最小二乘法线性回归运算方法,实例分析了给定一组点,用最小二乘法进行线性回归运算的实现技巧,具有一定参考借鉴价值,需要...

    北风其凉8912021-10-18
  • C#C# 后台处理图片的几种方法

    C# 后台处理图片的几种方法

    本篇文章主要介绍了C# 后台处理图片的几种方法,非常具有实用价值,需要的朋友可以参考下。...

    IT小伙儿10162021-12-08
  • C#聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题 新手速来围观

    聊一聊C#接口问题,新手速来围观,一个通俗易懂的例子帮助大家更好的理解C#接口问题,感兴趣的小伙伴们可以参考一下...

    zenkey7072021-12-03