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

Winapi 从非交互式服务(win32/.net/powershell)启动UAC提升进程,winapi,uac,shellexecute,createprocessasuser,Winapi,Uac,Shellexecute,Createprocessasuser,我正在使用第三方Windows服务,它通过使用CreateProcessAsUser()运行脚本和可执行文件来处理一些自动化任务。由于UAC和通过API处理LUA提升的方式,我在Windows Server 2008上遇到了问题 该服务以LocalSystem运行,未启用“与桌面交互”。这些进程是作为Administrators组中的用户运行的,而不是作为Administrator帐户运行的(该帐户不受许多UAC限制)。所有UAC默认设置均已就位 我可以向服务传递任意命令或powershell代

我正在使用第三方Windows服务,它通过使用CreateProcessAsUser()运行脚本和可执行文件来处理一些自动化任务。由于UAC和通过API处理LUA提升的方式,我在Windows Server 2008上遇到了问题

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

我可以向服务传递任意命令或powershell代码,但我似乎无法“突破”服务启动的非提升、非交互过程

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

我发现的唯一解决方法如下所述:

在Vista中,官方记录的方式 提升流程只需使用 shell API ShellExecute(Ex)(非 CreateProcess或CreateProcessAsUser)。 因此,您的应用程序必须调用 ShellExecute(Ex)以启动帮助程序 提升为调用SendInput。 此外,由于会话0 隔离,服务只能使用 CreateProcessAsUser或 CreateProcessWithLogonW(无法使用 ShellExecute(Ex))来指定 交互式桌面

…我认为没有直接的方法 从中派生提升的进程 windows服务。我们只能先用 CreateProcessAsUser或 CreateProcessWithLogonW生成一个 将非提升进程导入到用户中 会话(交互式桌面)。然后在 对于非提升过程,可以使用 ShellExecute(Ex)生成提升的 实际任务的流程

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

我还看了 和

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

如果有微软的人最终读到这篇文章,我注意到ShellExecute内部处理提升的方式是调用应用程序信息服务(AIS)。为什么不能通过一些Win32或.NET API调用AIS?

对不起,跑得有点长。谢谢你的建议。

打破会话零隔离的“官方”方法是结合使用终端服务API和
CreateProcessAsUser()
在用户会话中启动进程。在我以前的工作中,我们就是这样做的,因为我们需要在安装下载的更新之前从服务向用户显示一个对话框,所以我知道它至少在WinXP、Win2K3、Vista和Win7上工作,但我不认为Win2K8会有太大的不同。基本上,过程如下:

  • 调用
    WTSGetActiveConsoleSessionId()
    以获取活动的控制台会话id(非常重要,因为交互式会话不总是会话1,即使在客户端系统上也是如此)。如果没有活动用户登录到交互式会话(即本地登录到物理机器,而不是使用RDP),此API也将返回-1
  • 将上一个API调用中的会话id传递给
    WTSQueryUserToken()
    ,以获取一个打开的令牌,该令牌代表登录到控制台的用户
  • 调用
    DuplicateTokenEx()
    将模拟令牌(从
    WTSQueryUserToken
    )转换为主令牌
  • 调用
    CreateEnvironmentBlock()
    为流程创建一个新环境(可选,但如果您不这样做,流程将没有新环境)
  • 将步骤#3中的主令牌与可执行文件的命令行一起传递到对
    createProcessAsUser()
    的调用中。如果从步骤4创建了环境块,则还必须传递
    CREATE\u UNICODE\u environment
    标志(始终)。这可能看起来很愚蠢,但如果不这样做,API会失败得很厉害(带有
    ERROR\u INVALID\u parameter
  • 如果您创建了一个环境块,则需要调用
    DestroyEnvironmentBlock
    ,否则将产生内存泄漏。进程启动时会获得环境块的单独副本,因此您只销毁本地数据
  • 瞧!Windows执行了一些内部魔法,您可以看到应用程序启动。然而,尽管这将从服务启动和交互流程,但我不确定它是否会绕过UAC(但不要引用我的话)。换句话说,它可能不会作为提升的进程启动,除非注册表或内部清单要求这样做,即使这样,您仍然可能会收到UAC提示。如果从步骤#3获得的令牌是受限令牌,则可以使用
    AdjustTokenPrivileges()
    还原提升的(完整)令牌,但也不要引用我的话。但是,如MSDN文档中所述,请注意,不可能在尚未拥有特权的令牌上“添加”特权(例如,您不能通过使用
    AdjustTokenPrivileges
    ,将受限用户令牌转换为管理员;基础用户必须首先是管理员)

    从技术上讲,从Win2K forward可以完成所有这一切。然而,这实际上只有从Wi开始才可行