语境
在以管理员权限执行的 Windows 安装程序中,我想要配置一项服务,该服务将由专用用户(我们称之为该用户serviceUser
)运行。
为了设置的目的,我想运行另一个程序(检查配置是否正常的程序)serviceUser
。
我更像是一个 Linux 用户,并且我正在尝试运行以下命令:
sudo -u serviceUser myProgram -check
我尝试过
据我了解,在 Windows 上以另一个用户身份运行程序的 goto 实用程序似乎是RunAs
。
从 shell 中,我能够使用 RunAs 启动命令,例如:RunAs /user:DOMAIN\serviceUser "cmd.exe /C dir"
但我注意到我的用例存在一些问题:
该命令在另一个 shell 中启动,并且是异步的(例如:
RunAs ...
立即返回,而命令在后台执行)。
在我的用例中:我打算检查程序的退出代码,并读取其输出RunAs
首先启动时会询问密码serviceUser
,即使我RunAs
以管理员权限启动我不明白是否
RunAs
始终可用,或者是否需要在目标 Windows 系统上激活某些服务(“二次登录”服务?)
问题
- 有没有办法等待执行的程序
RunAs
退出,并捕获其输出? - 有没有办法以非交互的方式为用户提供凭据,或者直截了当地说“我是管理员,不要询问密码”?
- 我是否必须在主机系统上运行一些检查,以查看是否
RunAs
可用?
或者:从管理员 shell 运行时,是否有更直接的方式以非管理员用户身份执行程序?
答案1
RunAs 必须启动另一个 shell,因为它需要切换 shell 附加的权限令牌,而使用 Windows API 则无法做到这一点。
答案:
有没有办法等待 RunAs 执行的程序退出,并捕获其输出?
看这个答案 如何等待程序终止。
要捕获其输出,需要将其定向到文件,或者如果你愿意学习 PowerShell,可以使用
Tee-Object 命令
(可缩写为tee
)。
有没有办法以非交互的方式为用户提供凭据,或者直截了当地说“我是管理员,不要询问密码”?
您始终需要指定密码。但是,为了避免交互询问密码,您可以使用免费的 RunAs 代替 执行程序 这也允许在命令行上指定密码(不安全的做法)。
我是否必须在主机系统上运行一些检查来查看 RunAs 是否可用?
RunAs 是 Windows 的一部分,因此始终可用。
答案2
我将回答原始主题的问题,并部分回答第 2 和第 4 个问题,因为我非常有资格这样做。(我可能是地球上少数几个可以做到这一点的软件开发人员之一。)
这三个问题大致是相互关联的:
Windows:如何以不同的用户身份运行程序(相当于 linux‘sudo -u user cmd’)?
有没有办法以非交互的方式为用户提供凭据,或者直截了当地说“我是管理员,不要询问密码”?
从管理员 shell 运行时,是否有更直接的方法以非管理员用户身份执行程序?
您基本上正在寻找的答案就是我写的这个工具:
https://github.com/cubiclesoft/createprocess-windows
稍后我将介绍该工具本身。
我强烈推荐观看视频,它将为您提供关于 Windows 如何在后台运行以实现系统安全性的速成课程/入门课程。但我会尽力在这里总结该视频的内容。
问题在于,在用户和用户帐户方面,Windows 和 Linux 的底层有很大不同。Windows 中的基本安全对象是“安全令牌”,它是其他结构大杂烩的上层结构。要在 Windows 中启动进程,您必须拥有安全令牌。默认情况下,当前进程的令牌或在某些情况下线程令牌会被复制。安全令牌由不同的组件组成,例如用户安全标识符或 SID、所有者 SID、主组 SID、令牌所属的组 SID 列表、分配给令牌的权限、默认 DACL、提升状态以及大量杂项(其中一些非常没有记录)。问题是,说您想以不同的用户身份运行比听起来要复杂得多。即使在您当前的管理员用户中,您实际上也拥有两个安全令牌:您的非提升令牌和您的“链接”提升令牌。并且 Windows 没有简单的机制来在令牌之间切换(UAC 是一种系统服务,可帮助使用提升的令牌启动进程)。一旦进程开始运行(这是后面的关键!),进程令牌就无法更改。在 Linux 中,如果您是 root,您可以简单地说“我现在实际上是这个 UID”,Linux 将验证 root 并切换用户上下文,因为 UID + GID 是绝大多数 Linux 部署中安全性的上层结构,它们是简单的整数,使切换上下文相对容易。另一方面,Windows 中的 SID 是大小可变的二进制对象,每个令牌都有许多 SID,而令牌特权是众所周知的扳手。没有可进行比较/等价的东西。Windows 安全对象从根本上来说更复杂(我认为不是以一种好的方式)。
除此之外,假设你想继续制作您自己的安全令牌。Windows 中只有一个官方机构可以创建安全令牌,即本地安全机构子系统服务 (LSASS),并且每个公开的接口都需要凭据来创建令牌(即密码、硬件令牌或生物识别输入)。该服务最终调用未记录的NtCreateToken
API 来创建令牌。API首先NtCreateToken
需要调用该 API 的权限。很少有进程拥有。而获得现有进程令牌上您尚未拥有的权限介于“复杂”和“不可能”之间。此时,您已经进入了一个兔子洞,很少有人能毫发无损地回来。简而言之,作为普通用户甚至高级管理员,没有办法SeCreateTokenPrivilege
SeCreateTokenPrivilege
直接地以没有凭证的另一个用户身份启动进程。至少不是正式的。
但是,您可能会注意到 CreateProcess 工具声称它可以以其他用户的身份启动进程,而无需凭据。但它的工作原理绝对不是直接的,需要非常长的命令行,并且还有一些其他相当大的警告。以另一个用户身份启动子进程的过程(特别是在非提升环境中启动它时)在技术方面很长且复杂。简而言之,该工具通过启动一个新但暂停的子进程来工作。然后在临时的 NT 系统服务(我甚至不会讨论如何设置它)中,NtSetInformationProcess
(另一个未记录的 Windows 内核 API)被调用以将所需的令牌分配给暂停的子进程。只有在进程开始运行之前但在创建之后才能分配令牌(创建暂停的进程、分配令牌、启动主线程)。
您可以传递/createtoken
一组序列化选项来从头创建一个全新的令牌(即没有用户密码),但由于以下原因,启动的进程可能无法加载:此 Windows 加载程序与 imm32.dll 有关。因此,虽然命令提示符 (cmd.exe) 本身以其他用户身份启动时没有问题(可以使用 SysInternals Process Explorer 进行验证),但以该用户身份启动其他进程是有问题的,并且可能会或可能不会由于意外错误而工作。令牌或 imm32.dll 不喜欢的进程上下文出了问题。但是,以 NT AUTHORITY\SYSTEM 身份运行或从另一个正在运行的进程复制现有令牌似乎没有问题。也就是说,确实/createtoken
成功地为大多数用户创建了令牌而不需要该用户的凭据,并且该令牌可用于启动某些进程。所以在某种程度上,这可能回答了你的第二个问题。有点。需要更多的研究。
对于最后一个问题,从技术上讲,CreateProcess 工具用于该选项的类似机制/elevatedtoken
也可能用于选择和分配未提升的令牌给目标进程。该工具只是没有内置这种简化的支持。我可以看到一个用例,你以提升的管理员身份运行,但想要短暂地回到非提升状态,然后稍后返回到提升状态,而无需通过 UAC 对话框。所以也许/regulartoken
将来可以向该工具添加一个选项来适应这种情况。
请记住,所有这些都是高度实验性的,因为它调用了未记录的 Windows 内核 API。因此,它随时可能出现故障(例如 Windows 更新)。该工具已被 Windows Defender 标记为“恶意软件”至少一次,可能是因为它调用了所有不寻常的 API。(我认为 Windows Defender 并不是特别智能的软件。)但它不是恶意软件。只是有点不寻常。如果有任何问题,我建议使用 Visual C++ 构建它,因为源代码就在那里,任何人都可以查看/构建。