在 Windows 系统中,管理员权限和非管理员权限运行的程序之间不能使用 Windows 提供的通信机制进行通信。对于部分文件夹(ProgramData),管理员权限创建的文件是不能以非管理员权限修改和删除的。

然而,一个进程运行之后启动的子进程,会继承当前进程的 UAC 权限;于是有时我们会有降权运行的需要。本文将介绍 Windows 系统上降权运行的几种方法。


本文的降权运行指的是:

  1. 有一个 A 程序是以管理员权限运行的(典型的,如安装包);
  2. 有一个 B 程序会被 A 启动(我们期望降权运行的 B 程序)。

本文内容

  • 如何判断当前进程的 UAC 权限
  • 方法一:使用 runas 命令来运行程序(推荐)
  • 方法二:使用 explorer.exe 代理运行程序(推荐)
  • 方法三:在启动进程时传入用户名和密码
  • 方法四:使用 Shell 进程的 Access Token 来启动进程

如何判断当前进程的 UAC 权限

通过下面的代码,可以获得当前进程的 UAC 权限。

var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);

而如果要判断是否是管理员权限,则使用:

if (principal.IsInRole(WindowsBuiltInRole.Administrator))
{// 当前正在以管理员权限运行。
}

此代码如果在 .NET Core 中编写,需要额外安装 Windows 兼容包:Microsoft.Windows.Compatibility。+

方法一:使用 runas 命令来运行程序(推荐)

使用 runas 命令来运行,可以指定一个权限级别:

> runas /trustlevel:0x20000 "C:\Users\walterlv\Desktop\walterlv.exe"
var subProcessFileName = "C:\Users\walterlv\Desktop\walterlv.exe";
Process.Start("runas.exe", $"/trustlevel:0x20000 {subProcessFileName}");

关于 runas 的更多细节,可以参考我的另一篇博客:

  • Windows 下使用 runas 命令以指定的权限启动一个进程(非管理员、管理员) - 吕毅

方法二:使用 explorer.exe 代理运行程序(推荐)

因为绝大多数用户启动系统的时候,explorer.exe 进程都是处于运行状态,而如果启动一个新的 explorer.exe,都会自动激活当前正在运行的进程而不会启动新的。

于是我们可以委托默认以普通权限运行的 explorer.exe 来代理启动我们需要启动的子进程,这时启动的子进程便是与 explorer.exe 相同权限的,也就是降权运行了。

var subProcessFileName = "C:\Users\walterlv\Desktop\walterlv.exe";
Process.Start("explorer.exe", subProcessFileName);

通过以上代码,walterlv.exe 就会以与 explorer.exe 相同权限运行,也就是降权运行了。

下面的代码,如果发现自己是以管理员权限运行的,那么就降权重新运行自己,然后自己退出。

var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
{// 检测到当前进程是以管理员权限运行的,于是降权启动自己之后,把自己关掉。Process.Start("explorer.exe", Assembly.GetEntryAssembly().Location);Shutdown();return;
}

方法三:在启动进程时传入用户名和密码

ProcessStartInfo 中有 UserNamePassword 属性,设置此属性可以以此计算机上的另一个用户身份启动此进程。如果这个用户是普通用户,那么就会以普通权限运行此进程。

var processInfo = new ProcessStartInfo
{Verb = "runas",FileName = "walterlv.exe",UserName = "walterlv",Password = ReadPassword(),UseShellExecute = false,LoadUserProfile = true
};
Process.Start(processInfo);

上面的 ReadPassword 函数来自我的另一篇博客:如何让 .NET Core 命令行程序接受密码的输入而不显示密码明文 - walterlv。

然而,此方法最大的问题在于——产品级的程序,不可能也不应该知道用户的密码!所以实际上这样的方法并不实用。

方法四:使用 Shell 进程的 Access Token 来启动进程

此方法需要较多的 Windows API 调用,我没有尝试过这种方法,但是你可以自行尝试下面的链接:

  • c# - How do you de-elevate privileges for a child process - Stack Overflow

参考资料

  • c# starting process with lowered privileges from UAC admin level process - Stack Overflow
  • c# - How do you de-elevate privileges for a child process - Stack Overflow
  • c# - How do you de-elevate privileges for a child process - Stack Overflow
  • windows - Force a program to run without administrator privileges or UAC? - Super User
  • High elevation can be bad for your application: How to start a non-elevated process at the end of the installation - CodeProject
  • How to Enable Drag and Drop for an Elevated MFC Application on Vista/Windows 7 • Helge Klein

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

在 Windows 系统上降低 UAC 权限运行程序(从管理员权限降权到普通用户权限)相关推荐

  1. C# 普通权限运行程序\非管理员运行\降低权限运行

    一.目的与实际 1.VS设置管理员权限运行程序后,发现调用powershell命令或程序需要普通权限即可,Administrator权限反而错. 2.网上搜索关键字,大部分都是怎么使用管理员权限运行. ...

  2. 在32位WINDOWS系统上开发64位应用程序

    在32位WINDOWS系统上开发64位应用程序 创建 2011-9-2 有些时候需要开发WINDOWS 64位应用程序,但不想安装64位操作系统,所以需要在32位系统下开发64位应用.其步骤并不复杂. ...

  3. C++程序在Windows系统上启动失败与运行卡死问题排查实战

    目录 1.VS2017默认编译出来的程序,不支持XP系统 1.1.新版本软件为什么要选择VS2017?

  4. Windows 系统上使用任务管理器查看进程的各项属性(命令行、DPI、管理员权限等)

    Windows 系统上的任务管理器进化到 Windows 10 的 1809 版本后,又新增了几项可以查看的进程属性. 本文介绍可以使用任务管理器查看的各种进程属性. 本文内容 如何查看进程的各种属性 ...

  5. linux代码windows能跑吗,能不能帮忙改一下下面这些代码,原来是在windows系统上运行的,要让它能在linux上终端跑。该如何处理...

    当前位置:我的异常网» C语言 » 能不能帮忙改一下下面这些代码,原来是在windows系 能不能帮忙改一下下面这些代码,原来是在windows系统上运行的,要让它能在linux上终端跑.该如何处理 ...

  6. 启动root用户 银河麒麟_麒麟系统使用root权限运行程序

    最近在虚拟机里安装了个国产麒麟系统.(不知道麒麟系统的百度下.) ************************************************** PS:首次试用的同学可以先用 V ...

  7. 关闭Windows系统中的UAC用户帐户控制

    问题描述: 软件工具需要注册到注册表,无论使用普通用户权限或是管理员权限,注册始终失败. 解决思路: 通过控制UAC的通知等级,成功使得软件工具在非管理员权限下注册成功. 操作步骤: 1. Win+R ...

  8. 在Windows系统上使用WSL和Docker

    在Windows系统上使用WSL和Docker 文章目录 在Windows系统上使用WSL和Docker Windows的Linux子系统(WSL) WSL安装教程 在WSL上运行Linux GUI应 ...

  9. Redis进阶实践之三如何在Windows系统上安装安装Redis

    一.Redis的简介 Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset( ...

最新文章

  1. oracle为什么要创建数据库,手动创建Oracle数据库之前因后果
  2. 前端学习(2019)vue之电商管理系统电商系统处理attr参数
  3. 开源jumpserver 堡垒机搭建
  4. php自动发邮件系统,一个简单的自动发送邮件系统(二)_php基础
  5. python 中locals() 和 globals()的区别
  6. np.percentile获取中位数、百分位数
  7. Nginx 静态页面POST 请求提示405 Not Allowed
  8. js基础-11-相等和全等的区别
  9. python爬去学校_利用Python如何爬取自己学校的官网?用这招就行!
  10. 机电传动与控制【1】
  11. ESP32学习10:TcpClient
  12. sklearn垃圾邮件识别
  13. matlab powergui在哪儿,powergui模块在哪
  14. 菠萝来啦。新一代VueX 来啦 他有一个特别甜的名字“Pinia”,再不学你就out了【 Pinia/Vuex5中文文档】
  15. [常用类]Instant类的使用
  16. 如何执行IntelliJ IDEA 中的.sql文件
  17. oracle中todate函数实例,pl/sql to_date 函数使用实例讲解
  18. 面试被问:你了解的海康威视是一家怎样的公司?
  19. java的自省机制_JAVA内省(自省)机制 ( Introspector , BeanInfo, PropertyDescriptor )
  20. 大数据主要所学技术(简介)

热门文章

  1. java计算圆形的面积与周长_Java学习之路----计算圆形的面积和周长
  2. Red Hat Enterprise Linux (RHEL) 8.6 发布(含下载)
  3. Python提示:Consider using the `--user` option or check the permissions.
  4. windows端口映射
  5. 毫秒转换小时,分钟,秒,及颜色转换
  6. Mine Goose Duck 0.4版本发布
  7. python统计次数正则_Python提取信息必学基础——正则表达式
  8. 【WSL2】配置连接 USB 设备并使用主机的 USB 摄像头
  9. FPGA之简易DDS信号发生器设计
  10. with open相关用法