Chr*_*ars 16 winapi uac shellexecute createprocessasuser
我正在使用第三方Windows服务,通过使用CreateProcessAsUser()运行脚本和可执行文件来处理一些自动化任务.由于UAC,我在Windows Server 2008上遇到了问题,并且通过API处理LUA提升的方式.
该服务作为LocalSystem运行,并且未启用"Interact With Desktop".这些进程作为Administrators组中的用户运行,但不是管理员帐户(免除许多UAC限制).所有UAC默认设置都已到位.
我可以将任意命令或powershell代码传递给服务,但我似乎无法"突破"由服务启动的非提升的非交互式进程.
问题的症结似乎是启动提升过程的唯一(公共)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.此外,由于Session 0隔离,服务只能使用CreateProcessAsUser或CreateProcessWithLogonW(不能使用ShellExecute(Ex))来指定交互式桌面.
..我认为没有直接的方法从Windows服务产生提升的进程.我们只能首先使用CreateProcessAsUser或CreateProcessWithLogonW将非提升的进程生成到用户会话(交互式桌面)中.然后在非提升的进程中,它可以使用ShellExecute(Ex)为真实任务生成提升的进程.
要从.net/powershell代码执行此操作,看起来我必须做一些精心设计的P/Invoke来调用CreateProcessAsUser或CreateProcessWithLogonW,因为.Net System.Diagnostics.ProcessStartInfo没有相应的lpDesktop,我可以设置为"winsta0\default".而且我不清楚LocalSystem是否有权调用CreateProcessAsUser或CreateProcessWithLogonW.
我还查看了 http://blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessas-in-net.aspx 和 Process.Start与UAC的不同凭据
基于这一切,我得出结论,没有直接的方法来做到这一点.我错过了什么吗?这看起来真的不应该那么难.感觉UAC从未被设计用于处理非交互式用例.
如果有任何微软人员最终阅读此内容,我注意到ShellExecute内部处理提升的方式是通过调用应用程序信息服务(AIS).为什么通过某些Win32或.NET API不能同样调用AIS? http://msdn.microsoft.com/en-us/library/bb756945.aspx
抱歉,跑了一会儿.谢谢你的任何想法.
Jav*_*t93 17
打破会话零隔离的"官方"方法是使用终端服务API的组合并CreateProcessAsUser()在用户会话中启动进程.在我以前的工作中,我们就是这么做的,因为我们需要在安装下载更新之前从服务中向用户显示一个对话框所以,我知道它至少可以在WinXP,Win2K3,Vista和Win7上运行,但是我不要指望Win 2K8会有太大的不同.基本上,过程如下:
WTSGetActiveConsoleSessionId()以获取活动的控制台会话ID(非常重要,因为交互式会话并非总是会话1,即使在客户端系统上也是如此).如果没有活动用户登录交互式会话(即,本地登录到物理机,而不是使用RDP),此API也将返回-1.WTSQueryUserToken()以获取表示登录到控制台的用户的开放令牌.DuplicateTokenEx()将模拟令牌(从WTSQueryUserToken)转换为主令牌.CreateEnvironmentBlock()为流程创建一个新环境(可选,但如果不这样做,则流程将没有).CreateProccessAsUser()与可执行文件的命令行一起传递给调用.如果您从步骤#4创建了一个环境块,则还必须CREATE_UNICODE_ENVIRONMENT(始终)传递该标志.这可能看起来很愚蠢,但如果你不这样做,API就会失败ERROR_INVALID_PARAMTER.DestroyEnvironmentBlock,否则会产生内存泄漏.该过程在启动时会获得一个单独的环境块副本,因此您只会销毁本地数据.瞧!Windows做了一些内部魔术,你看到应用程序启动.但是,虽然这将从服务启动和交互过程,但我不确定它是否会绕过UAC(但不要引用我的话).换句话说,除非注册表或内部清单表明这样做,否则它可能无法作为提升的进程启动,即便如此,您仍可能会获得UAC提示.如果从步骤#3获得的令牌是受限令牌,您可以使用它AdjustTokenPrivileges()来恢复提升(完整)令牌,但也不要引用我.但是,如MSDN文档中所述,请注意,无法在尚未拥有它们的令牌上"添加"权限(例如,您无法通过使用将受限用户令牌转换为管理员AdjustTokenPrivileges;
从技术上讲,可以从Win2K向前完成所有这些工作.但是,它实际上只能从WinXP开始,因为Win2K缺少WTSGetActiveConsoleSessionId()和WTSQueryUserToken()API(以及WTSEnumerateProcesses()Win2K Pro).您可以硬编码0作为会话ID(因为在Win2K中总是如此),我想您可以通过枚举正在运行的进程并复制其中一个令牌来获取用户令牌(它应该是一个交互式SID存在).无论如何,CreateProcessAsUser()即使您没有从服务设置中选择"与桌面交互",传递交互式用户令牌时的行为也会相同.它也比直接从服务启动更安全,因为该进程不会继承敬虔的LocalSystem访问令牌.
现在,我不知道你的第三方应用程序在运行脚本/进程时是否会执行此操作,但如果你想从服务中执行此操作,那就是这样的(并且使用Vista或Win7,这是唯一的方法克服会话0隔离).