- 修正 WTS 会话相关类型、枚举与活动会话选择逻辑 - 对齐 FILE_ID_DESCRIPTOR 布局与 FILE_ID_TYPE 语义,修复 OpenFileById 调用前提 - 修正 user32/shell32/kernel32 部分 API 的返回值、参数个数与错误处理 - 完善剪贴板更新格式读取的缓冲区重试逻辑 - 补充常用进程、线程、调试、桌面与会话 helper - 增加结构体布局、会话查询、剪贴板、CreateProcess 等回归测试 - 将默认 CreateProcess 相关测试切到 helper 进程,并保留显式开启的 cmd.exe 集成覆盖
296 lines
7.5 KiB
Go
296 lines
7.5 KiB
Go
package win32api
|
|
|
|
import (
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
func DuplicateTokenEx(hExistingToken HANDLE, dwDesiredAccess DWORD,
|
|
lpTokenAttributes uintptr, ImpersonationLevel int,
|
|
TokenType TOKEN_TYPE, phNewToken *TOKEN) error {
|
|
|
|
Dup, err := getProcAddr("advapi32.dll", "DuplicateTokenEx")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, errno := syscall.Syscall6(Dup, 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), lpTokenAttributes, uintptr(ImpersonationLevel),
|
|
uintptr(TokenType), uintptr(unsafe.Pointer(phNewToken)))
|
|
if r == 0 {
|
|
return error(errno)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func CreateProcessAsUser(hToken TOKEN, lpApplicationName, lpCommandLine string,
|
|
lpProcessAttributes, lpThreadAttributes, bInheritHandles uintptr,
|
|
dwCreationFlags DWORD, lpEnvironment HANDLE, lpCurrentDirectory string,
|
|
lpStartupInfo *StartupInfo, lpProcessInformation *ProcessInformation) error {
|
|
var (
|
|
applicationName uintptr
|
|
commandLine uintptr
|
|
workingDir uintptr
|
|
)
|
|
CPAU, err := getProcAddr("advapi32.dll", "CreateProcessAsUserW")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(lpApplicationName) > 0 {
|
|
applicationName = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpApplicationName)))
|
|
}
|
|
if len(lpCommandLine) > 0 {
|
|
commandLine = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpCommandLine)))
|
|
}
|
|
if len(lpCurrentDirectory) > 0 {
|
|
workingDir = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpCurrentDirectory)))
|
|
}
|
|
r, _, errno := syscall.Syscall12(CPAU, 11, uintptr(hToken), applicationName,
|
|
commandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, uintptr(dwCreationFlags), uintptr(lpEnvironment),
|
|
workingDir, uintptr(unsafe.Pointer(lpStartupInfo)), uintptr(unsafe.Pointer(lpProcessInformation)), 0)
|
|
if r == 0 {
|
|
return error(errno)
|
|
}
|
|
return nil
|
|
}
|
|
func GetTokenInformation(TokenHandle HANDLE, TokenInformationClass, TokenInformation,
|
|
TokenInformationLength uintptr, ReturnLength *uintptr) error {
|
|
GTI, err := getProcAddr("advapi32.dll", "GetTokenInformation")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if r, _, errno := syscall.Syscall6(GTI, 5, uintptr(TokenHandle), TokenInformationClass,
|
|
TokenInformation, TokenInformationLength, uintptr(unsafe.Pointer(ReturnLength)), 0); r == 0 {
|
|
return error(errno)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func GetUserName() (string, error) {
|
|
gun, err := getProcAddr("advapi32.dll", "GetUserNameW")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
size := uint32(64)
|
|
for {
|
|
buf := make([]uint16, size)
|
|
n := uint32(len(buf))
|
|
r, _, errno := syscall.Syscall(gun, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0)
|
|
if r != 0 {
|
|
return syscall.UTF16ToString(buf), nil
|
|
}
|
|
if errno == syscall.ERROR_INSUFFICIENT_BUFFER {
|
|
if n > size {
|
|
size = n
|
|
} else {
|
|
size *= 2
|
|
}
|
|
continue
|
|
}
|
|
if errno != 0 {
|
|
return "", error(errno)
|
|
}
|
|
return "", syscall.EINVAL
|
|
}
|
|
}
|
|
|
|
func OpenProcessToken(ProcessHandle HANDLE, DesiredAccess DWORD, TokenHandle *TOKEN) error {
|
|
if TokenHandle == nil {
|
|
return syscall.EINVAL
|
|
}
|
|
proc, err := getProcAddr("advapi32.dll", "OpenProcessToken")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, errno := syscall.Syscall(proc, 3, uintptr(ProcessHandle), uintptr(DesiredAccess), uintptr(unsafe.Pointer(TokenHandle)))
|
|
if r == 0 {
|
|
if errno != 0 {
|
|
return error(errno)
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func CheckTokenMembership(tokenHandle HANDLE, sidToCheck unsafe.Pointer) (bool, error) {
|
|
if sidToCheck == nil {
|
|
return false, syscall.EINVAL
|
|
}
|
|
proc, err := getProcAddr("advapi32.dll", "CheckTokenMembership")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
var isMember int32
|
|
r, _, errno := syscall.Syscall(proc, 3,
|
|
uintptr(tokenHandle),
|
|
uintptr(sidToCheck),
|
|
uintptr(unsafe.Pointer(&isMember)),
|
|
)
|
|
if r == 0 {
|
|
if errno != 0 {
|
|
return false, error(errno)
|
|
}
|
|
return false, syscall.EINVAL
|
|
}
|
|
return isMember != 0, nil
|
|
}
|
|
|
|
func LookupPrivilegeValue(lpSystemName, lpName string, lpLuid *LUID) error {
|
|
if lpLuid == nil {
|
|
return syscall.EINVAL
|
|
}
|
|
proc, err := getProcAddr("advapi32.dll", "LookupPrivilegeValueW")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var systemNamePtr uintptr
|
|
if len(lpSystemName) > 0 {
|
|
systemNamePtr = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpSystemName)))
|
|
}
|
|
r, _, errno := syscall.Syscall(proc, 3,
|
|
systemNamePtr,
|
|
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpName))),
|
|
uintptr(unsafe.Pointer(lpLuid)),
|
|
)
|
|
if r == 0 {
|
|
if errno != 0 {
|
|
return error(errno)
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func AdjustTokenPrivileges(TokenHandle TOKEN, DisableAllPrivileges bool, NewState *TOKEN_PRIVILEGES, BufferLength DWORD,
|
|
PreviousState *TOKEN_PRIVILEGES, ReturnLength *DWORD) error {
|
|
proc, err := getProcAddr("advapi32.dll", "AdjustTokenPrivileges")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
disableAll := uintptr(0)
|
|
if DisableAllPrivileges {
|
|
disableAll = 1
|
|
}
|
|
r, _, errno := syscall.Syscall6(proc, 6,
|
|
uintptr(TokenHandle),
|
|
disableAll,
|
|
uintptr(unsafe.Pointer(NewState)),
|
|
uintptr(BufferLength),
|
|
uintptr(unsafe.Pointer(PreviousState)),
|
|
uintptr(unsafe.Pointer(ReturnLength)),
|
|
)
|
|
if r == 0 {
|
|
if errno != 0 {
|
|
return error(errno)
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
if errno == windows.ERROR_NOT_ALL_ASSIGNED {
|
|
return error(errno)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func RevertToSelf() error {
|
|
proc, err := getProcAddr("advapi32.dll", "RevertToSelf")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, errno := syscall.Syscall(proc, 0, 0, 0, 0)
|
|
if r == 0 {
|
|
if errno != 0 {
|
|
return error(errno)
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func CreateProcessWithToken(hToken TOKEN, dwLogonFlags DWORD, lpApplicationName, lpCommandLine string,
|
|
dwCreationFlags DWORD, lpEnvironment HANDLE, lpCurrentDirectory string,
|
|
lpStartupInfo *StartupInfo, lpProcessInformation *ProcessInformation) error {
|
|
var (
|
|
applicationName uintptr
|
|
commandLine uintptr
|
|
currentDir uintptr
|
|
)
|
|
if len(lpApplicationName) > 0 {
|
|
applicationName = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpApplicationName)))
|
|
}
|
|
if len(lpCommandLine) > 0 {
|
|
commandLine = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpCommandLine)))
|
|
}
|
|
if len(lpCurrentDirectory) > 0 {
|
|
currentDir = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpCurrentDirectory)))
|
|
}
|
|
|
|
proc, err := getProcAddr("advapi32.dll", "CreateProcessWithTokenW")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r, _, errno := syscall.Syscall12(proc, 9,
|
|
uintptr(hToken),
|
|
uintptr(dwLogonFlags),
|
|
applicationName,
|
|
commandLine,
|
|
uintptr(dwCreationFlags),
|
|
uintptr(lpEnvironment),
|
|
currentDir,
|
|
uintptr(unsafe.Pointer(lpStartupInfo)),
|
|
uintptr(unsafe.Pointer(lpProcessInformation)),
|
|
0,
|
|
0,
|
|
0,
|
|
)
|
|
if r == 0 {
|
|
if errno != 0 {
|
|
return error(errno)
|
|
}
|
|
return syscall.EINVAL
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func IsTokenElevated(token TOKEN) (bool, error) {
|
|
var elevation TOKEN_ELEVATION
|
|
var retLen uintptr
|
|
if err := GetTokenInformation(
|
|
HANDLE(token),
|
|
TokenElevation,
|
|
uintptr(unsafe.Pointer(&elevation)),
|
|
uintptr(unsafe.Sizeof(elevation)),
|
|
&retLen,
|
|
); err != nil {
|
|
return false, err
|
|
}
|
|
return elevation.TokenIsElevated != 0, nil
|
|
}
|
|
|
|
func IsCurrentProcessElevated() (bool, error) {
|
|
processHandle, err := syscall.GetCurrentProcess()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
var token TOKEN
|
|
if err := OpenProcessToken(HANDLE(processHandle), TOKEN_QUERY, &token); err != nil {
|
|
return false, err
|
|
}
|
|
defer func() {
|
|
_ = CloseHandle(HANDLE(token))
|
|
}()
|
|
return IsTokenElevated(token)
|
|
}
|
|
|
|
func IsCurrentUserInAdminGroup() (bool, error) {
|
|
adminSID, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
// Passing tokenHandle=0 lets Windows use the calling thread/process effective token.
|
|
return CheckTokenMembership(0, unsafe.Pointer(adminSID))
|
|
}
|