From d1fd9fc41cff07e25e67fad53a478d10452b6aae Mon Sep 17 00:00:00 2001 From: kruskall <99559985+kruskall@users.noreply.github.com> Date: Sun, 11 Aug 2024 00:17:27 +0200 Subject: [PATCH 1/2] refactor: deprecate old methods and point to upstream lib deprecate methods implemented in the upstream x/sys/windows library --- constants.go | 8 +--- go.mod | 2 +- go.sum | 4 +- kernel32.go | 17 ++++---- ntdll.go | 21 ++++------ psapi.go | 5 ++- version.go | 55 ++++++++---------------- zsyscall_windows.go | 100 ++++---------------------------------------- 8 files changed, 49 insertions(+), 163 deletions(-) diff --git a/constants.go b/constants.go index 4dfc905..637a168 100644 --- a/constants.go +++ b/constants.go @@ -21,13 +21,9 @@ package windows const ( - // This process access rights are missing from Go's syscall package as of 1.10.3 - - // PROCESS_VM_READ right allows to read memory from the target process. + // Deprecated: use x/sys/windows PROCESS_VM_READ = 0x10 - // PROCESS_QUERY_LIMITED_INFORMATION right allows to access a subset of the - // information granted by PROCESS_QUERY_INFORMATION. Not available in XP - // and Server 2003. + // Deprecated: use x/sys/windows PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 ) diff --git a/go.mod b/go.mod index 2819c6f..e3e88e3 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/stretchr/testify v1.9.0 - golang.org/x/sys v0.18.0 + golang.org/x/sys v0.24.0 ) require ( diff --git a/go.sum b/go.sum index 2387471..8487a78 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/kernel32.go b/kernel32.go index d66f887..d916b2e 100644 --- a/kernel32.go +++ b/kernel32.go @@ -26,6 +26,8 @@ import ( "syscall" "time" "unsafe" + + "golang.org/x/sys/windows" ) // Syscalls @@ -33,7 +35,6 @@ import ( //sys _GetTickCount64() (millis uint64, err error) = kernel32.GetTickCount64 //sys _GetSystemTimes(idleTime *syscall.Filetime, kernelTime *syscall.Filetime, userTime *syscall.Filetime) (err error) = kernel32.GetSystemTimes //sys _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) = kernel32.GlobalMemoryStatusEx -//sys _ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, buffer uintptr, size uintptr, numRead *uintptr) (err error) = kernel32.ReadProcessMemory //sys _GetProcessHandleCount(handle syscall.Handle, pdwHandleCount *uint32) (err error) = kernel32.GetProcessHandleCount var ( @@ -224,18 +225,16 @@ func GlobalMemoryStatusEx() (MemoryStatusEx, error) { return memoryStatusEx, nil } -// ReadProcessMemory reads from another process memory. The Handle needs to have -// the PROCESS_VM_READ right. -// A zero-byte read is a no-op, no error is returned. -func ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, dest []byte) (numRead uintptr, err error) { +// Deprecated: use x/sys/windows +func ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, dest []byte) (uintptr, error) { n := len(dest) if n == 0 { return 0, nil } - if err = _ReadProcessMemory(handle, baseAddress, uintptr(unsafe.Pointer(&dest[0])), uintptr(n), &numRead); err != nil { - return 0, err - } - return numRead, nil + + var numRead uintptr + err := windows.ReadProcessMemory(windows.Handle(handle), baseAddress, &dest[0], uintptr(n), &numRead) + return numRead, err } // GetProcessHandleCount retrieves the number of open handles of a process. diff --git a/ntdll.go b/ntdll.go index 7982fd4..0c85a61 100644 --- a/ntdll.go +++ b/ntdll.go @@ -24,6 +24,8 @@ import ( "fmt" "syscall" "unsafe" + + "golang.org/x/sys/windows" ) const ( @@ -108,20 +110,11 @@ type RtlUserProcessParameters struct { CommandLine UnicodeString } -// Syscalls -// Warning: NtQueryInformationProcess is an unsupported API that can change -// in future versions of Windows. Available from XP to Windows 10. -//sys _NtQueryInformationProcess(handle syscall.Handle, infoClass uint32, info uintptr, infoLen uint32, returnLen *uint32) (ntStatus uint32) = ntdll.NtQueryInformationProcess - -// NtQueryInformationProcess is a wrapper for ntdll.NtQueryInformationProcess. -// The handle must have the PROCESS_QUERY_INFORMATION access right. -// Returns an error of type NTStatus. -func NtQueryInformationProcess(handle syscall.Handle, infoClass ProcessInfoClass, info unsafe.Pointer, infoLen uint32) (returnedLen uint32, err error) { - status := _NtQueryInformationProcess(handle, uint32(infoClass), uintptr(info), infoLen, &returnedLen) - if status != 0 { - return returnedLen, NTStatus(status) - } - return returnedLen, nil +// Deprecated: use x/sys/windows +func NtQueryInformationProcess(handle syscall.Handle, infoClass ProcessInfoClass, info unsafe.Pointer, infoLen uint32) (uint32, error) { + var returnedLen uint32 + err := windows.NtQueryInformationProcess(windows.Handle(handle), int32(infoClass), info, infoLen, &returnedLen) + return returnedLen, err } // Error prints the wrapped NTSTATUS in hex form. diff --git a/psapi.go b/psapi.go index 01fcf10..7e5380d 100644 --- a/psapi.go +++ b/psapi.go @@ -24,12 +24,13 @@ import ( "fmt" "syscall" "unsafe" + + "golang.org/x/sys/windows" ) // Syscalls //sys _GetProcessMemoryInfo(handle syscall.Handle, psmemCounters *ProcessMemoryCountersEx, cb uint32) (err error) = psapi.GetProcessMemoryInfo //sys _GetProcessImageFileNameA(handle syscall.Handle, imageFileName *byte, nSize uint32) (len uint32, err error) = psapi.GetProcessImageFileNameA -//sys _EnumProcesses(lpidProcess *uint32, cb uint32, lpcbNeeded *uint32) (err error) = psapi.EnumProcesses var ( sizeofProcessMemoryCountersEx = uint32(unsafe.Sizeof(ProcessMemoryCountersEx{})) @@ -90,7 +91,7 @@ func GetProcessImageFileName(handle syscall.Handle) (string, error) { func EnumProcesses() (pids []uint32, err error) { for nAlloc, nGot := uint32(128), uint32(0); ; nAlloc *= 2 { pids = make([]uint32, nAlloc) - if err = _EnumProcesses(&pids[0], nAlloc*4, &nGot); err != nil { + if err = windows.EnumProcesses(pids, &nGot); err != nil { return nil, err } if nGot/4 < nAlloc { diff --git a/version.go b/version.go index f049d3f..d17fba5 100644 --- a/version.go +++ b/version.go @@ -24,17 +24,11 @@ import ( "errors" "fmt" "unsafe" -) -// Syscalls -//sys _GetFileVersionInfo(filename string, reserved uint32, dataLen uint32, data *byte) (success bool, err error) [!success] = version.GetFileVersionInfoW -//sys _GetFileVersionInfoSize(filename string, handle uintptr) (size uint32, err error) = version.GetFileVersionInfoSizeW -//sys _VerQueryValueW(data *byte, subBlock string, pBuffer *uintptr, len *uint32) (success bool, err error) [!success] = version.VerQueryValueW + "golang.org/x/sys/windows" +) -// FixedFileInfo contains version information for a file. This information is -// language and code page independent. This is an equivalent representation of -// VS_FIXEDFILEINFO. -// https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx +// Deprecated: use x/sys/windows type FixedFileInfo struct { Signature uint32 StrucVersion uint32 @@ -83,25 +77,20 @@ func (d VersionData) QueryValue(key string) (string, error) { CodePage uint16 } - var dataPtr uintptr - var size uint32 - if _, err := _VerQueryValueW(&d[0], `\VarFileInfo\Translation`, &dataPtr, &size); err != nil || size == 0 { + var langCodePage *LangAndCodePage + langCodeLen := uint32(unsafe.Sizeof(*langCodePage)) + if err := windows.VerQueryValue(unsafe.Pointer(&d[0]), `\VarFileInfo\Translation`, (unsafe.Pointer)(&langCodePage), &langCodeLen); err != nil || langCodeLen == 0 { return "", fmt.Errorf("failed to get list of languages: %w", err) } - offset := int(dataPtr - (uintptr)(unsafe.Pointer(&d[0]))) - if offset <= 0 || offset > len(d)-1 { - return "", errors.New("invalid address") - } - - l := *(*LangAndCodePage)(unsafe.Pointer(&d[offset])) - - subBlock := fmt.Sprintf(`\StringFileInfo\%04x%04x\%v`, l.Language, l.CodePage, key) - if _, err := _VerQueryValueW(&d[0], subBlock, &dataPtr, &size); err != nil || size == 0 { + var dataPtr uintptr + var size uint32 + subBlock := fmt.Sprintf(`\StringFileInfo\%04x%04x\%v`, langCodePage.Language, langCodePage.CodePage, key) + if err := windows.VerQueryValue(unsafe.Pointer(&d[0]), subBlock, (unsafe.Pointer)(&dataPtr), &size); err != nil || langCodeLen == 0 { return "", fmt.Errorf("failed to query %v: %w", subBlock, err) } - offset = int(dataPtr - (uintptr)(unsafe.Pointer(&d[0]))) + offset := int(dataPtr - (uintptr)(unsafe.Pointer(&d[0]))) if offset <= 0 || offset > len(d)-1 { return "", errors.New("invalid address") } @@ -118,38 +107,30 @@ func (d VersionData) QueryValue(key string) (string, error) { // version-information resource. It queries the root block to get the // VS_FIXEDFILEINFO value. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx -func (d VersionData) FixedFileInfo() (*FixedFileInfo, error) { +func (d VersionData) FixedFileInfo() (*windows.VS_FIXEDFILEINFO, error) { if len(d) == 0 { return nil, errors.New("use GetFileVersionInfo to initialize VersionData") } - var dataPtr uintptr - var size uint32 - if _, err := _VerQueryValueW(&d[0], `\`, &dataPtr, &size); err != nil { + var fixedInfo *windows.VS_FIXEDFILEINFO + fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo)) + if err := windows.VerQueryValue(unsafe.Pointer(&d[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen); err != nil { return nil, fmt.Errorf("VerQueryValue failed for \\: %w", err) } - offset := int(dataPtr - (uintptr)(unsafe.Pointer(&d[0]))) - if offset <= 0 || offset > len(d)-1 { - return nil, errors.New("invalid address") - } - - // Make a copy of the struct. - ffi := *(*FixedFileInfo)(unsafe.Pointer(&d[offset])) - - return &ffi, nil + return fixedInfo, nil } // GetFileVersionInfo retrieves version information for the specified file. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647003(v=vs.85).aspx func GetFileVersionInfo(filename string) (VersionData, error) { - size, err := _GetFileVersionInfoSize(filename, 0) + size, err := windows.GetFileVersionInfoSize(filename, nil) if err != nil { return nil, fmt.Errorf("GetFileVersionInfoSize failed: %w", err) } data := make(VersionData, size) - _, err = _GetFileVersionInfo(filename, 0, uint32(len(data)), &data[0]) + err = windows.GetFileVersionInfo(filename, 0, uint32(len(data)), unsafe.Pointer(&data[0])) if err != nil { return nil, fmt.Errorf("GetFileVersionInfo failed: %w", err) } diff --git a/zsyscall_windows.go b/zsyscall_windows.go index 67b5add..c1bf5b1 100644 --- a/zsyscall_windows.go +++ b/zsyscall_windows.go @@ -58,23 +58,15 @@ func errnoErr(e syscall.Errno) error { var ( modkernel32 = windows.NewLazySystemDLL("kernel32.dll") - modntdll = windows.NewLazySystemDLL("ntdll.dll") modpsapi = windows.NewLazySystemDLL("psapi.dll") - modversion = windows.NewLazySystemDLL("version.dll") - - procGetNativeSystemInfo = modkernel32.NewProc("GetNativeSystemInfo") - procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount") - procGetSystemTimes = modkernel32.NewProc("GetSystemTimes") - procGetTickCount64 = modkernel32.NewProc("GetTickCount64") - procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") - procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory") - procNtQueryInformationProcess = modntdll.NewProc("NtQueryInformationProcess") - procEnumProcesses = modpsapi.NewProc("EnumProcesses") - procGetProcessImageFileNameA = modpsapi.NewProc("GetProcessImageFileNameA") - procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") - procGetFileVersionInfoSizeW = modversion.NewProc("GetFileVersionInfoSizeW") - procGetFileVersionInfoW = modversion.NewProc("GetFileVersionInfoW") - procVerQueryValueW = modversion.NewProc("VerQueryValueW") + + procGetNativeSystemInfo = modkernel32.NewProc("GetNativeSystemInfo") + procGetProcessHandleCount = modkernel32.NewProc("GetProcessHandleCount") + procGetSystemTimes = modkernel32.NewProc("GetSystemTimes") + procGetTickCount64 = modkernel32.NewProc("GetTickCount64") + procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") + procGetProcessImageFileNameA = modpsapi.NewProc("GetProcessImageFileNameA") + procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") ) func _GetNativeSystemInfo(systemInfo *SystemInfo) { @@ -115,28 +107,6 @@ func _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) { return } -func _ReadProcessMemory(handle syscall.Handle, baseAddress uintptr, buffer uintptr, size uintptr, numRead *uintptr) (err error) { - r1, _, e1 := syscall.Syscall6(procReadProcessMemory.Addr(), 5, uintptr(handle), uintptr(baseAddress), uintptr(buffer), uintptr(size), uintptr(unsafe.Pointer(numRead)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func _NtQueryInformationProcess(handle syscall.Handle, infoClass uint32, info uintptr, infoLen uint32, returnLen *uint32) (ntStatus uint32) { - r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(handle), uintptr(infoClass), uintptr(info), uintptr(infoLen), uintptr(unsafe.Pointer(returnLen)), 0) - ntStatus = uint32(r0) - return -} - -func _EnumProcesses(lpidProcess *uint32, cb uint32, lpcbNeeded *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(lpidProcess)), uintptr(cb), uintptr(unsafe.Pointer(lpcbNeeded))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - func _GetProcessImageFileNameA(handle syscall.Handle, imageFileName *byte, nSize uint32) (len uint32, err error) { r0, _, e1 := syscall.Syscall(procGetProcessImageFileNameA.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(imageFileName)), uintptr(nSize)) len = uint32(r0) @@ -153,57 +123,3 @@ func _GetProcessMemoryInfo(handle syscall.Handle, psmemCounters *ProcessMemoryCo } return } - -func _GetFileVersionInfoSize(filename string, handle uintptr) (size uint32, err error) { - var _p0 *uint16 - _p0, err = syscall.UTF16PtrFromString(filename) - if err != nil { - return - } - return __GetFileVersionInfoSize(_p0, handle) -} - -func __GetFileVersionInfoSize(filename *uint16, handle uintptr) (size uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetFileVersionInfoSizeW.Addr(), 2, uintptr(unsafe.Pointer(filename)), uintptr(handle), 0) - size = uint32(r0) - if size == 0 { - err = errnoErr(e1) - } - return -} - -func _GetFileVersionInfo(filename string, reserved uint32, dataLen uint32, data *byte) (success bool, err error) { - var _p0 *uint16 - _p0, err = syscall.UTF16PtrFromString(filename) - if err != nil { - return - } - return __GetFileVersionInfo(_p0, reserved, dataLen, data) -} - -func __GetFileVersionInfo(filename *uint16, reserved uint32, dataLen uint32, data *byte) (success bool, err error) { - r0, _, e1 := syscall.Syscall6(procGetFileVersionInfoW.Addr(), 4, uintptr(unsafe.Pointer(filename)), uintptr(reserved), uintptr(dataLen), uintptr(unsafe.Pointer(data)), 0, 0) - success = r0 != 0 - if !success { - err = errnoErr(e1) - } - return -} - -func _VerQueryValueW(data *byte, subBlock string, pBuffer *uintptr, len *uint32) (success bool, err error) { - var _p0 *uint16 - _p0, err = syscall.UTF16PtrFromString(subBlock) - if err != nil { - return - } - return __VerQueryValueW(data, _p0, pBuffer, len) -} - -func __VerQueryValueW(data *byte, subBlock *uint16, pBuffer *uintptr, len *uint32) (success bool, err error) { - r0, _, e1 := syscall.Syscall6(procVerQueryValueW.Addr(), 4, uintptr(unsafe.Pointer(data)), uintptr(unsafe.Pointer(subBlock)), uintptr(unsafe.Pointer(pBuffer)), uintptr(unsafe.Pointer(len)), 0, 0) - success = r0 != 0 - if !success { - err = errnoErr(e1) - } - return -} From 5a9d15deee8f1a5d836207d1be68adb000426999 Mon Sep 17 00:00:00 2001 From: kruskall <99559985+kruskall@users.noreply.github.com> Date: Sun, 11 Aug 2024 00:42:29 +0200 Subject: [PATCH 2/2] fix: undeprecate versioninfo struct --- version.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/version.go b/version.go index d17fba5..6c92d32 100644 --- a/version.go +++ b/version.go @@ -28,7 +28,10 @@ import ( "golang.org/x/sys/windows" ) -// Deprecated: use x/sys/windows +// FixedFileInfo contains version information for a file. This information is +// language and code page independent. This is an equivalent representation of +// VS_FIXEDFILEINFO. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx type FixedFileInfo struct { Signature uint32 StrucVersion uint32 @@ -107,12 +110,12 @@ func (d VersionData) QueryValue(key string) (string, error) { // version-information resource. It queries the root block to get the // VS_FIXEDFILEINFO value. // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647464(v=vs.85).aspx -func (d VersionData) FixedFileInfo() (*windows.VS_FIXEDFILEINFO, error) { +func (d VersionData) FixedFileInfo() (*FixedFileInfo, error) { if len(d) == 0 { return nil, errors.New("use GetFileVersionInfo to initialize VersionData") } - var fixedInfo *windows.VS_FIXEDFILEINFO + var fixedInfo *FixedFileInfo fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo)) if err := windows.VerQueryValue(unsafe.Pointer(&d[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen); err != nil { return nil, fmt.Errorf("VerQueryValue failed for \\: %w", err)