如何从Windows服务锁定工作站?

时间:2010-03-17 23:16:22

标签: .net windows-services locking

我需要从用VB.Net编写的Windows服务锁定工作站。我在Windows 7上编写应用程序,但它也需要在Vista和XP下运行。

User32 API LockWorkStation无法正常工作,因为它需要一个交互式桌面,我的返回值为0.

我尝试从进程和Shell调用%windir%\ System32 \ rundll32.exe user32.dll,LockWorkStation,但仍然没有任何反应。

将服务设置为与桌面交互是不行的,因为我在管理员帐户下运行服务,因此它可以执行一些需要管理员权限的其他内容 - 例如禁用网络,并且您只能选择交互如果在本地系统帐户下运行,则使用桌面选项。

这将是次要问题 - 如何在不影响用户的情况下从本地系统帐户下运行的服务运行具有管理员权限的其他应用程序。

我正在编写一个应用程序来控制我的孩子电脑/互联网访问(我计划在完成后开源)所以我需要尽可能隐秘地发生所有事情。

我有一个用于处理任务栏中的设置和状态通知的UI,但这很容易被杀死,从而无法锁定。我可以创建另一个隐藏的Windows窗体应用程序来处理锁定,但这似乎是一个相当不优雅的解决方案。

更好的想法?

6 个答案:

答案 0 :(得分:5)

我一直在与这个斗争一周,在阅读了很多关于这个问题的信息后,终于得到了解决方案...

您必须使用CreateProcessAsUser函数,如下所示:

  Private Shared Sub Executer(ByVal content As String)
    Dim objProcess As System.Diagnostics.Process

    Dim filename As String
    filename = "e:\lock.bat" 
    'create a bat file with ''rundll32.exe user32.dll,LockWorkStation'' inside

    Dim UserTokenHandle As IntPtr = IntPtr.Zero
    WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)

    Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
    Dim StartInfo As New WindowsApi.STARTUPINFOW
    StartInfo.cb = CUInt(Marshal.SizeOf(StartInfo))

    WindowsApi.CreateProcessAsUser(UserTokenHandle, filename, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
    If Not UserTokenHandle = IntPtr.Zero Then
        WindowsApi.CloseHandle(UserTokenHandle)
    End If

End Sub

获取here中的大部分代码,您也可以找到与此功能一起使用的WindowsApi。 我仍然试图找到是否可以避免蝙蝠文件,但至少是一个非常好的解决方案。

编辑: 要避免使用外部* .bat文件来执行代码,只需编辑WindowsApi类并使用以下命令替换CreateProcessAsUser和advapi32.dll导入部分:

    <DllImport("Advapi32.dll", EntryPoint:="CreateProcessAsUser", ExactSpelling:=False,      SetLastError:=True, CharSet:=CharSet.Unicode)> _
    Public Shared Function CreateProcessAsUser( _
                       ByVal hToken As IntPtr, _
                       ByVal lpApplicationName As String, _
                       <[In](), Out(), [Optional]()> ByVal lpCommandLine As StringBuilder, _
                       ByVal lpProcessAttributes As IntPtr, _
                       ByVal lpThreadAttributes As IntPtr, _
                       <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandles As Boolean, _
                       ByVal dwCreationFlags As Integer, _
                       ByVal lpEnvironment As IntPtr, _
                       ByVal lpCurrentDirectory As String, _
                       <[In]()> ByRef lpStartupInfo As STARTUPINFOW, _
                       <Out()> ByRef lpProcessInformation As PROCESS_INFORMATION) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

现在你可以使用stringbuilder作为CreateProcessAsUser函数的thrid参数(comandline),并将第二个(applicationame)设置为'Nothing',如下所示:

Dim cmdline As New StringBuilder
cmdline.Append("rundll32.exe user32.dll,LockWorkStation")
WindowsApi.CreateProcessAsUser(UserTokenHandle, Nothing, cmdline, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)

它会工作!!!!

此致 AP

答案 1 :(得分:2)

你正在尝试做的事情被微软主动阻止 - 如果你确实让它发挥作用,它就会利用一个肯定会很快关闭的漏洞。

你可以做的是Friar Tuck/Robin Hood解决方案 - 有两个程序在运行并相互监控。当一个人被杀死时,另一个人会检测到并重新启动它(或者,只是将当前用户记录为惩罚,具体取决于你想要的严重程度)。

答案 2 :(得分:1)

另一个不优雅的解决方案(但没有信号通知你的UI应用程序的缺点)是安装另一个服务来与桌面进行交互,而桌面的工作就是监听锁定桌面的信号。

我同意必须使用本地系统凭据运行并不是很好,但如果所有服务都锁定了桌面,则需要保护的内存非常小。

答案 3 :(得分:0)

您可以尝试从自动锁定工作站的Windows服务启动屏幕保护程序。

答案 4 :(得分:0)

对我的回答并不完全满意,但Window的安全性让我没有其他选择。任何打开的服务(通过Process,Shell等)都不会有桌面访问权限。我理解微软创造的限制背后的原因,但仍然令人沮丧!

我的服务使用IPC告诉我的用户界面锁定计算机。以下是执行此操作的基本链接:

http://anoriginalidea.wordpress.com/2007/08/09/simple-inter-process-communication-in-vbnet/

请参阅他的参考链接以获取更多数据。

然而,这仍然不太奏效。如果没有Access Is Denied消息,请参阅此链接以了解如何操作:

http://social.msdn.microsoft.com/Forums/en-US/windowssecurity/thread/ce968b5b-04fe-46d2-bb75-73e367a8b0c3

确保您的URI正确无误。服务器端的portName属性是GetObject方法调用中IPC路径的第一部分。第二部分映射到服务器端RegisterWellKnownServiceType调用的第二个参数。

显然portName属性在服务器端和客户端都需要不同。

如果“连接到IPC端口失败:系统找不到指定的文件”。在你的客户端上,服务器还没有启动,所以没有什么可以听到你尖叫。

答案 5 :(得分:0)

为了与服务中的用户会话进行交互,您首先需要使用用户会话ID。基本上,您需要在调用WTSGetActiveConsoleSessionId之前使用WTSGetActiveConsoleSessionIdCreateEnvironmentBlockCreateProcessAsUser
重要的部分是CreateEnvironmentBlock。前两种方法允许我们不要使用期望的用户名/密码。 用作将工作站从服务锁定的概念证明的Python代码段如下所示:

import win32process
import win32con
import win32ts

console_session_id = win32ts.WTSGetActiveConsoleSessionId()
console_user_token = win32ts.WTSQueryUserToken(console_session_id)
startup = win32process.STARTUPINFO()
priority = win32con.NORMAL_PRIORITY_CLASS
environment = win32profile.CreateEnvironmentBlock(console_user_token, False)
handle, thread_id ,pid, tid = win32process.CreateProcessAsUser(console_user_token, None, "rundll32.exe user32.dll,LockWorkStation", None, None, True, priority, environment, None, startup)

ref