From 12cec1faf1ba925d7b0a3a355d32aa819eac98ba Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 13 Nov 2020 15:51:52 +0100 Subject: [PATCH] windows: add IsWow64Process2 for detecting x86 on arm The original IsWow64Process returns false on arm, always, and so IsWow64Process2 was added to account for this scenario. This isn't available on older versions of Windows, so we mark it as such using the new '?' notation. Finally, we add a test to make sure this all works and does the expected thing on different versions of Windows. Change-Id: Ic0412578cfb3f4cf6c9dc92a0028abc579bf6c85 Reviewed-on: https://go-review.googlesource.com/c/sys/+/269077 Run-TryBot: Jason A. Donenfeld TryBot-Result: Go Bot Reviewed-by: Brad Fitzpatrick Trust: Jason A. Donenfeld --- windows/syscall_windows.go | 1 + windows/syscall_windows_test.go | 28 ++++++++++++++++++++++++++++ windows/zsyscall_windows.go | 13 +++++++++++++ 3 files changed, 42 insertions(+) diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 008ffc11..3b6c5ae7 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -174,6 +174,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW //sys ExitProcess(exitcode uint32) //sys IsWow64Process(handle Handle, isWow64 *bool) (err error) = IsWow64Process +//sys IsWow64Process2(handle Handle, processMachine *uint16, nativeMachine *uint16) (err error) = IsWow64Process2? //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW //sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) //sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index 2f1513f3..cb03e1d5 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go @@ -5,6 +5,8 @@ package windows_test import ( + "debug/pe" + "errors" "fmt" "io/ioutil" "os" @@ -458,3 +460,29 @@ func TestJobObjectInfo(t *testing.T) { t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have) } } + +func TestIsWow64Process2(t *testing.T) { + var processMachine, nativeMachine uint16 + err := windows.IsWow64Process2(windows.CurrentProcess(), &processMachine, &nativeMachine) + if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) { + maj, min, build := windows.RtlGetNtVersionNumbers() + if maj < 10 || (maj == 10 && min == 0 && build < 17763) { + t.Skip("not available on older versions of Windows") + return + } + } + if err != nil { + t.Fatalf("IsWow64Process2 failed: %v", err) + } + if processMachine == pe.IMAGE_FILE_MACHINE_UNKNOWN { + processMachine = nativeMachine + } + switch { + case processMachine == pe.IMAGE_FILE_MACHINE_AMD64 && runtime.GOARCH == "amd64": + case processMachine == pe.IMAGE_FILE_MACHINE_I386 && runtime.GOARCH == "386": + case processMachine == pe.IMAGE_FILE_MACHINE_ARMNT && runtime.GOARCH == "arm": + case processMachine == pe.IMAGE_FILE_MACHINE_ARM64 && runtime.GOARCH == "arm64": + default: + t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine) + } +} diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index d400c351..cc5d74f5 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -248,6 +248,7 @@ var ( procGetVolumePathNamesForVolumeNameW = modkernel32.NewProc("GetVolumePathNamesForVolumeNameW") procGetWindowsDirectoryW = modkernel32.NewProc("GetWindowsDirectoryW") procIsWow64Process = modkernel32.NewProc("IsWow64Process") + procIsWow64Process2 = modkernel32.NewProc("IsWow64Process2") procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW") procLoadLibraryW = modkernel32.NewProc("LoadLibraryW") procLocalFree = modkernel32.NewProc("LocalFree") @@ -2055,6 +2056,18 @@ func IsWow64Process(handle Handle, isWow64 *bool) (err error) { return } +func IsWow64Process2(handle Handle, processMachine *uint16, nativeMachine *uint16) (err error) { + err = procIsWow64Process2.Find() + if err != nil { + return + } + r1, _, e1 := syscall.Syscall(procIsWow64Process2.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(processMachine)), uintptr(unsafe.Pointer(nativeMachine))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) { var _p0 *uint16 _p0, err = syscall.UTF16PtrFromString(libname)