// Copyright (c) 2026 S.A. (SNOWARE). Written for SCU Team. // Licensed under MulanPubL-2.0. // You may obtain a copy at: http://license.coscl.org.cn/MulanPubL-2.0 // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND. // Package winperm 提供 Windows UAC 管理员权限检测与提权。 package perm import ( "os" "syscall" "unsafe" "gitee.com/snoware/swlib/logger" ) // Permission 权限管理器,封装管理员检测和提权操作。 type Permission struct{} // 预加载 shell32.dll 中的 Windows API。 var ( shell32 = syscall.NewLazyDLL("shell32.dll") isUserAnAdmin = shell32.NewProc("IsUserAnAdmin") shellExecuteW = shell32.NewProc("ShellExecuteW") ) // NewPermission 创建 Permission 实例。 func NewPermission() *Permission { return &Permission{} } // HasUAC 调用 IsUserAnAdmin 检查当前进程是否以管理员权限运行。 // 返回 true 表示已拥有管理员权限。 func (p *Permission) HasUAC() bool { ret, _, _ := isUserAnAdmin.Call() hasAdmin := ret != 0 logger.Log.Debug().Bool("has_admin", hasAdmin).Msg("检查管理员权限") return hasAdmin } // RunExeAsAdmin 通过 ShellExecuteW("runas") 以管理员身份启动指定的可执行文件。 // // 参数 exe: 目标可执行文件的绝对路径。 // 成功时当前进程应退出,由新的管理员进程接管。 func (p *Permission) RunExeAsAdmin(exe string) error { logger.Log.Info().Str("exe", exe).Msg("尝试以管理员身份运行") verb := "runas" cwd, _ := os.Getwd() verbPtr, _ := syscall.UTF16PtrFromString(verb) exePtr, _ := syscall.UTF16PtrFromString(exe) cwdPtr, _ := syscall.UTF16PtrFromString(cwd) var showCmd int32 = 1 // SW_NORMAL ret, _, _ := shellExecuteW.Call( 0, uintptr(unsafe.Pointer(verbPtr)), uintptr(unsafe.Pointer(exePtr)), 0, uintptr(unsafe.Pointer(cwdPtr)), uintptr(showCmd), ) if ret <= 32 { err := syscall.GetLastError() logger.Log.Error().Err(err).Int32("ret", int32(ret)).Msg("管理员提权失败") return err } logger.Log.Info().Msg("管理员提权成功,当前进程将退出") return nil } // GetSelf 获取当前可执行文件的绝对路径。 func (p *Permission) GetSelf() (string, error) { exe, err := os.Executable() if err != nil { logger.Log.Error().Err(err).Msg("获取自身可执行文件路径失败") return "", err } logger.Log.Debug().Str("exe_path", exe).Msg("获取自身路径") return exe, nil } // RunSelfAsAdmin 以管理员身份重新执行自身。 // 返回当前可执行文件路径和可能的错误。 func (p *Permission) RunSelfAsAdmin() (string, error) { exe, err := p.GetSelf() if err != nil { return "", err } err = p.RunExeAsAdmin(exe) return exe, err }