代码之家  ›  专栏  ›  技术社区  ›  Brad Mathews

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

  •  3
  • Brad Mathews  · 技术社区  · 15 年前

    我需要从用vb.net编写的Windows服务锁定工作站。我正在Windows7上编写这个应用程序,但它也需要在Vista和XP下工作。

    user32 api lockworkstation不工作,因为它需要一个交互式桌面,我得到的返回值为0。

    我尝试从进程和shell调用%windir%\system32\rundll32.exe user32.dll和lockworkstation,但仍然没有任何结果。

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

    这将是第二个问题-如何从在本地系统帐户下运行的服务运行另一个具有管理权限的应用程序,而无需对用户进行调试。

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

    我有一个在任务栏中处理设置和状态通知的用户界面,但是这很容易被杀死,从而破坏了锁定。我可以制作另一个隐藏的Windows窗体应用来处理锁定,但这似乎是一个相当不好的解决方案。

    有更好的主意吗?

    5 回复  |  直到 15 年前
        1
  •  5
  •   Adriano Pedro    10 年前

    我已经为此斗争了一个多星期,在阅读了很多关于这个问题的信息之后,终于找到了解决这个问题的方法…

    您必须使用这样的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函数的第三个参数(comandline),并将第二个参数(applicationName)设置为“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

        2
  •  2
  •   overslacked    15 年前

    你想做的是被微软主动阻止——如果你真的让它工作了,它会利用一个很快就会被关闭的漏洞。

    但你能做的是 Friar Tuck/Robin Hood 解决方案-让两个程序运行并相互监控。当其中一个被杀死时,另一个会检测到这一点并重新启动它(或者,根据您希望的严重程度,只需将当前用户注销作为惩罚)。

        3
  •  1
  •   Michael Burr    15 年前

    另一个不好的解决方案(但不存在向用户界面应用程序发送信号的缺点)是安装另一个服务来与桌面交互,桌面的任务是监听信号来锁定桌面。

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

        4
  •  0
  •   SoftwareGeek    15 年前

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

        5
  •  0
  •   Brad Mathews    15 年前

    我对我的回答并不完全满意,但窗户的安全让我别无选择。任何打开的bu服务(通过进程、shell等)都不能访问桌面。我理解微软所造成的限制背后的原因,但仍然令人沮丧!

    我的服务使用工控机告诉我的用户界面锁定计算机。下面是一个基本的链接:

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

    有关其他数据,请参阅他的参考链接。

    然而,这仍然不太管用。另请参阅此链接,了解如何在不访问被拒绝消息的情况下执行此操作:

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

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

    显然,在服务器端和客户机端,portname属性必须是不同的。

    如果您“未能连接到IPC端口:系统找不到指定的文件”。在您的客户机上,服务器还没有启动,因此没有听到您的尖叫声。