win32api/advapi32.go
starainrt 0f82ba044b
修正 Win32 封装语义并补齐关键结构体/进程测试覆盖
- 修正 WTS 会话相关类型、枚举与活动会话选择逻辑
- 对齐 FILE_ID_DESCRIPTOR 布局与 FILE_ID_TYPE 语义,修复 OpenFileById 调用前提
- 修正 user32/shell32/kernel32 部分 API 的返回值、参数个数与错误处理
- 完善剪贴板更新格式读取的缓冲区重试逻辑
- 补充常用进程、线程、调试、桌面与会话 helper
- 增加结构体布局、会话查询、剪贴板、CreateProcess 等回归测试
- 将默认 CreateProcess 相关测试切到 helper 进程,并保留显式开启的 cmd.exe 集成覆盖
2026-06-06 17:46:02 +08:00

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))
}