当前位置: 首页 > news >正文

go 编译的 windows 进程(exe)以管理员权限启动(UAC)

引言

windows 系统,在打开某些 exe 的时候,会弹出“用户账户控制(UAC)”的弹窗 “你要允许来自xx发布者的此应用对你的设备进行更改吗?”

UACUser Account Control,用户账户控制)是 Windows 操作系统中的一个安全组件,如果程序未通过管理员权限启动,在涉及一些敏感操作时可能会导致应用程序发生错误。

本篇简单介绍 2 种在 go 中以管理员权限启动程序的方式。

实现

这里介绍 2 种方式:

  1. manifest,使用 github.com/akavel/rsrc 库,一般都这么用。
  2. 运行时重新启动,动态提权。

一、manifest

标准的方式,通过嵌入清单文件触发 UAC 提示。

1. 创建 app.manifest 文件,内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"><security><requestedPrivileges><requestedExecutionLevel level="requireAdministrator" uiAccess="false"/></requestedPrivileges></security></trustInfo>
</assembly>

2. 嵌入清单到 go 程序

  1. 安装 rsrc 工具
go get github.com/akavel/rsrc
  1. 生成资源文件
rsrc -manifest app.manifest -o app.syso# -arch 平台
# -manifest  manifest文件,可以添加管理员权限启动
# -ico  图标文件
# -o  目标文件(.syso)
# rsrc -arch amd64 -manifest app.manifest -o app.syso -ico favicon.ico

3. 编译 go 程序

直接 go build 即可,**注意:上述通过 rsrc 生成的 syso 需要放到项目路径进行 build **。

二、动态提权

适用于应用程序并不是所有的操作都需要使用管理员权限,只在用户需要的时候进行提示,然后重启应用动态提权。

直接上代码,主要函数解释:

  • isAdmin():通过尝试访问系统设备检测权限。
  • runAsAdmin():使用 ShellExecute 以管理员权限重新启动程序。
package mainimport ("fmt""os""syscall""time""github.com/google/uuid""golang.org/x/sys/windows"
)// 判断程序是否为管理员启动,不是则需要重启// 检测当前是否以管理员权限运行
func isAdmin() bool {_, err := os.Open("\\\\.\\PHYSICALDRIVE0")return err == nil
}// 以管理员权限重新启动进程,并传递事件名称
func runAsAdmin(eventName string) error {exe, _ := os.Executable()args := fmt.Sprintf(`--event-name "%s"`, eventName) // 传递事件名称verbPtr, _ := syscall.UTF16PtrFromString("runas")exePtr, _ := syscall.UTF16PtrFromString(exe)argsPtr, _ := syscall.UTF16PtrFromString(args)cwd, _ := os.Getwd()cwdPtr, _ := syscall.UTF16PtrFromString(cwd)showCmd := int32(windows.SW_NORMAL)return windows.ShellExecute(0, verbPtr, exePtr, argsPtr, cwdPtr, showCmd)
}// 父进程等待事件触发
func waitForChildReady(eventName string) bool {// 创建事件对象(初始状态为未触发)event, err := windows.CreateEvent(nil, // 默认安全属性0,   // 手动重置(false表示自动重置)0,   // 初始状态未触发windows.StringToUTF16Ptr(eventName),)if err != nil {fmt.Println("CreateEvent error:", err)return false}defer windows.CloseHandle(event)// 等待事件触发(最多10秒)const timeout = 10 * time.Secondresult, err := windows.WaitForSingleObject(event, uint32(timeout.Milliseconds()))if err != nil {fmt.Println("WaitForSingleObject error:", err)return false}return result == windows.WAIT_OBJECT_0
}// 子进程触发事件
func signalParent(eventName string) {// 打开事件对象(需要EVENT_MODIFY_STATE权限)event, err := windows.OpenEvent(windows.EVENT_MODIFY_STATE,false,windows.StringToUTF16Ptr(eventName),)if err != nil {fmt.Println("OpenEvent error:", err)os.Exit(1)}defer windows.CloseHandle(event)// 触发事件if err := windows.SetEvent(event); err != nil {fmt.Println("SetEvent error:", err)os.Exit(1)}
}func main() {// 解析命令行参数中的事件名称var eventName stringfor i, arg := range os.Args {if arg == "--event-name" && i+1 < len(os.Args) {eventName = os.Args[i+1]break}}if isAdmin() {// 管理员模式下,触发事件并执行业务逻辑if eventName != "" {signalParent(eventName)}fmt.Println("以管理员模式启动!")// TODO: 主程序逻辑fmt.Println("按任意键退出程序...")// 直接从标准输入读取一个字节,用于检测按键操作buf := make([]byte, 1)os.Stdin.Read(buf)} else {// 非管理员模式,生成唯一事件名称并重启eventName := uuid.New().String()if err := runAsAdmin(eventName); err != nil {fmt.Println("Failed to restart as admin:", err)os.Exit(1)}// 等待子进程就绪if waitForChildReady(eventName) {fmt.Println("Child process started successfully.")os.Exit(0)} else {fmt.Println("Failed to start child process.")os.Exit(1)}}
}

相关文章:

  • Redis 共享和独立集群两种模式各自的优缺点是什么?
  • 【AI工具】2025年主流自动化技术(供参考)
  • 表格识别版面还原分析-GO语言集成-表格文字识别接口
  • 微信小程序 van-dropdown-menu
  • 2026《数据结构》考研复习笔记五(栈、队列)
  • MQTTX + MCP:MQTT 客户端秒变物联网 Agent
  • 安宝特科技 | AR眼镜在安保与安防领域的创新应用及前景
  • 激光SLAM算法综述
  • 基于Python的多光谱遥感数据处理与分类技术实践—以农作物分类与NDVI评估为例
  • Linux 系统监控大师:Glances 工具详解助力自动化
  • Codigger Desktop:Boby形象互动提升用户体验
  • 【HTTPS协议原理】数据加密、如何防止中间人攻击、证书和签名、HTTPS完整工作流程
  • [创业之路-376]:企业法务 - 创业,不同的企业形态,个人承担的风险、收益、税费、成本不同
  • elasticsearch 查询检索
  • java进阶之git
  • webpack详细打包配置,包含性能优化、资源处理...
  • Docker离线安装与配置指南
  • weibo_har鸿蒙微博分享,单例二次封装,鸿蒙微博,微博登录
  • 几种电气绝缘类型
  • Java求职面试:从Spring Boot到微服务的全面考核
  • 黎巴嫩“伊斯兰集团”组织证实其高级成员在以军空袭中丧生
  • 41岁知名学者陈昊因病骤然离世,北大再发讣告缅怀
  • 如何保护人工智能领域的知识产权?上海市知识产权局局长解答
  • 发布近百条《原神》涉密游戏内容,游戏资讯网站被判赔33万元
  • 路面突陷大坑致车毁人亡,家属称不知谁来管,长治当地回应
  • 魔都眼|上海半马鸣枪:白金标运动员、“箱根之子”齐参赛