C#穿透session隔离———Windows服务启动UI交互程序
写在前面
一开始是因为服务器经常会出现断电、系统崩溃的情况,导致一些正常运行的winform程序在系统故障重启后,每次都需要手动登录触发事件让程序自启。然后想利用windows服务在开启时就会自启来实现开机启动Winform程序。
但是因为从Vista 开始引入了 Session 0 隔离机制,导致windows服务无法直接进行界面交互操作。
注意:
使用CreateProcessAsUser与界面交互需要Session Id >0 ,用户会话的必须存在,如果存在服务器重启、注销后,重新开机导致系统只有Session 0存在,此时服务调用后的程序是不会显示界面的。
所以到头来还是没能实现我的想法。。。淦
Session 0 隔离原理
参考:
在早期的Windows操作系统中,在同一用户下运行的所有进程有着相同的安全等级,拥有相同的权限。例如,一个进程可以自由地发送一个Windows消息到另外一个进程的窗口。从Windows Vista开始,当然也包括Windows 7、Windows 10,对于某些Windows消息,这一方式再也行不通了。进程(或者其他的对象)开始拥有一个新的属性——特权等级(Privilege Level)。一个特权等级较低的进程不再可以向一个特权等级较高的进程发送消息,虽然他们在相同的用户权限下运行。这就是所谓的用户界面特权隔离(User Interface Privilege Isolation ,UIPI)。
UIPI的引入,最大的目的是防止恶意代码发送消息给那些拥有较高权限的窗口以对其进行攻击,从而获取较高的权限等等,在计算机系统中,这却是一种维护系统安全的合适方式。
windows服务启动UI程序、
对于简单的交互,服务可以通过WTSSendMessage 函数,在用户Session 上显示消息窗口。对于一些复杂的UI 交互,必须调用CreateProcessAsUser 或其他方法(WCF、.NET远程处理等)进行跨Session 通信,在桌面用户上创建一个应用程序界面。
解决思路是:window service创建一个和与当前登陆用户可以交互的进程,这个进程运行在admin权限下,能够调起应用程序的UI
具体的做法是:widow service复制winlogon.exe进程句柄,然后通过调用api函数CreateProcessAsUser()以winlogon.exe权限创建新进程,新创建的进程有winlogon.exe的权限(winlogon.exe运行在system权限下),负责调用程序。
作者原文:
First, we are going to create a Windows Service that runs under the System account. This service will be responsible for spawning an interactive process within the currently active User’s Session. This newly created process will display a UI and run with full admin rights. When the first User logs on to the computer, this service will be started and will be running in Session0; however the process that this service spawns will be running on the desktop of the currently logged on User. We will refer to this service as the LoaderService.
Next, the winlogon.exe process is responsible for managing User login and logout procedures. We know that every User who logs on to the computer will have a unique Session ID and a corresponding winlogon.exe process associated with their Session. Now, we mentioned above, the LoaderService runs under the System account. We also confirmed that each winlogon.exe process on the computer runs under the System account. Because the System account is the owner of both the LoaderService and the winlogon.exe processes, our LoaderService can copy the access token (and Session ID) of the winlogon.exe process and then call the Win32 API function CreateProcessAsUser to launch a process into the currently active Session of the logged on User. Since the Session ID located within the access token of the copied winlogon.exe process is greater than 0, we can launch an interactive process using that token.
参考:
交互式服务
C#开发Windows服务详细流程
C#穿透session隔离———Windows服务启动UI交互程序
Subverting Vista UAC in Both 32 and 64 bit Architectures
问题
windows服务启动winform程序不显示UI问题解决
原因:
xp系统的用户和window service运行在一个session下,在xp以后,windows系统改变了用户会话管理的策略,window service独立运行在session0下,依次给后续的登录用户分配sessionX(X =1,2,3…),session0没有权限运行UI。所以在window xp以后的系统下,window service调用有UI的application时只能看到程序进程但不能运行程序的UI。
参考:
C# windows服务启动winform程序不显示UI问题解决
How can a Windows service execute a GUI application?
穿透Session 0 隔离(二)
C#穿透session隔离———Windows服务启动UI交互程序
https://yuanjianzhang.github.io/2021/07/21/CSharp穿透session隔离———Windows服务启动UI交互程序/