代码之家  ›  专栏  ›  技术社区  ›  Chris Sears

从非交互式服务(win32/.net/powershell)启动UAC提升的进程

  •  15
  • Chris Sears  · 技术社区  · 16 年前

    该服务作为本地系统运行,未启用“与桌面交互”。这些进程是以Administrators组中的用户身份运行的,而不是以Administrator帐户(该帐户不受许多UAC限制)的身份运行的。所有UAC默认设置都已就位。

    问题的关键似乎是,启动提升进程的唯一(公共)API选项是带有“runas”动词的ShellExecute(),但据我所知,它不能从非交互式服务调用,或者会出现类似“此操作需要交互式窗口站”的错误。

    http://www.eggheadcafe.com/software/aspnet/29620442/how-to-proper-use-sendinp.aspx

    在Vista中,官方记录的方式 提升流程只是使用 shell API ShellExecute(Ex)(非 CreateProcess或CreateProcessAsUser)。 所以你的申请必须 ShellExecute(Ex)启动助手 提升为调用SendInput。 CreateProcessAsUser或 ShellExecute(Ex))来指定

    …我认为没有直接的方法 从 windows服务。我们只能先用 CreateProcessAsUser或 CreateProcessWithLogonW生成 非提升进程到用户中 非提升过程,它可以使用 ShellExecute(Ex)生成提升的

    要从.net/powershell代码中执行此操作,似乎我必须执行一些复杂的P/Invoke操作来调用CreateProcessAsUser或CreateProcessWithLogonW,因为.net System.Diagnostics.ProcessStartInfo没有可以设置为“winsta0\default”的lpDesktop的等效项。我不清楚LocalSystem是否有权调用CreateProcessAsUser或CreateProcessWithLogonW。

    我还看了 http://blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspx Process.Start with different credentials with UAC on

    基于这些,我得出的结论是,没有直接的方法可以做到这一点。我错过什么了吗?这看起来真的不应该这么难。感觉UAC从来没有被设计来处理非交互用例。

    如果有微软的人读到这篇文章,我注意到ShellExecute内部处理提升的方式是调用应用程序信息服务(AIS)。为什么不能通过Win32或.NET API调用AIS? http://msdn.microsoft.com/en-us/library/bb756945.aspx

    抱歉,跑得太久了。谢谢你的建议。

    2 回复  |  直到 9 年前
        1
  •  19
  •   Ajay    15 年前

    CreateProcessAsUser() 在用户会话中启动进程。在我以前的工作中,我们就是这样做的,因为我们需要在安装下载的更新之前从服务向用户显示一个对话框,所以,我知道它至少在WinXP、Win2K3、Vista和Win7上可以工作,但我不认为win2k8会有太大的不同。基本上,过程如下:

    1. WTSGetActiveConsoleSessionId() 获取活动控制台会话id(非常重要,因为交互式会话是 -1 如果没有活动用户登录到交互会话(即,本地登录到物理机器,而不是使用RDP)。
    2. WTSQueryUserToken() 获取代表登录到控制台的用户的打开令牌。
    3. DuplicateTokenEx() 转换模拟令牌(从 WTSQueryUserToken )变成一个主令牌。
    4. CreateEnvironmentBlock() 为流程创建一个新环境(可选,但如果没有,流程将没有环境)。
    5. CreateProccessAsUser() ,以及可执行文件的命令行。如果从步骤4创建了环境块,则必须通过 CREATE_UNICODE_ENVIRONMENT 旗子也是(总是)。这看起来可能很愚蠢,但是如果不这样做,API会失败得很惨(使用 ERROR_INVALID_PARAMTER ).
    6. DestroyEnvironmentBlock ,否则将生成内存泄漏。当进程启动时,它将获得环境块的一个单独副本,因此您只销毁本地数据。

    瞧!Windows做了一些内部魔术,你会看到应用程序启动。然而,尽管这将从一个服务启动和交互过程,我不确定它是否会绕过UAC(但不要引用我的话)。换句话说,它可能不会作为提升的进程启动,除非注册表或内部清单指示这样做,即使这样,您仍可能得到UAC提示。如果您从步骤#3获得的代币是受限代币,您可以使用 AdjustTokenPrivileges() AdjustTokenPrivileges ; 基础用户必须是管理员才能开始)。

    从技术上讲,从Win2K开始就可以做到这一切。然而,它实际上只从WinXP开始是可行的,因为Win2K缺少 和 API(以及 WTSEnumerateProcesses() CreateProcessAsUser() 即使您没有从服务设置中选择“与桌面交互”,在传递交互用户令牌时也会以相同的方式进行操作。无论如何,它也比直接从服务启动更安全,因为进程不会继承神的旨意 LocalSystem 访问令牌。

    现在,我不知道您的第三方应用程序在运行脚本/进程时是否会执行这些操作,但如果您希望从服务执行这些操作,则是这样(对于Vista或Win7,这是克服会话0隔离的唯一方法)。

        2
  •  1
  •   Joshua    13 年前

    根据你的用例,你可以做我所做的。我查找活动会话的winlogon进程并窃取其令牌。如果没有活动会话(API返回-1),如果WINVER>=6否则为0。这将导致系统处于活动会话状态。