确定当前进程是否在Go中运行在WOW64中还是非WOW64中

huangapple go评论88阅读模式
英文:

Determining if current process runs in WOW64 or not in Go

问题

使用Windows,官方的方法来判断当前的32位进程是否在32位或64位架构上运行(即是否在WOW64上运行)是调用kernel32.dll中的IsWow64Process函数,并查看其是否存在(根据我理解的文档)。

在Go语言中,我们可以使用syscall包调用dll文件中导出的函数,下面是我的尝试:

package main

import (
	"fmt"
	"os"
	"syscall"
)

func main() {
	dll, err := syscall.LoadDLL("kernel32.dll")
	if err != nil {
		fmt.Println(err)
	}
	defer dll.Release()
	proc, err := dll.FindProc("IsWow64Process")
	if err != nil {
		fmt.Println("Proc not found") // 不是WOW64,所以是32位系统?
		fmt.Println(err)
	}
	fmt.Printf("%v\n", proc)

	var handle uintptr = uintptr(os.Getpid())

	var result uintptr
	v, x, y := proc.Call(handle, result)

	fmt.Printf("%v %v %v\n", v, x, y)
	fmt.Printf("%v\n", result)
}

不幸的是,无论是在WOW64系统上还是在非WOW64系统上进行测试,标准输出都显示相同的结果:

&{0x10ada110 IsWow64Process 2088961457}
0 7 The handle is invalid.
0

我做错了什么?如何进行测试以确定我们的32位Go程序是在64位CPU上的模拟32位环境(WOW64)上运行,还是在真正的32位Windows上运行?

英文:

With Windows, the official way of guessing if the current 32-bit process is running on a 32 or 64-bit architecture (so on WOW64 or not) is to call the IsWow64Process function from kernel32.dll, and see if it is present (as I understand the doc).

In Go we can call functions exported in dll files with the syscall package, so here is my attempt:

package main

import (
	"fmt"
	"os"
	"syscall"
)

func main() {
	dll, err := syscall.LoadDLL("kernel32.dll")
	if err != nil {
		fmt.Println(err)
	}
	defer dll.Release()
	proc, err := dll.FindProc("IsWow64Process")
	if err != nil {
		fmt.Println("Proc not found") // not a WOW64 so a 32 bit system?
		fmt.Println(err)
	}
	fmt.Printf("%v\n", proc)

	var handle uintptr = uintptr(os.Getpid())

	var result uintptr
	v, x, y := proc.Call(handle, result)

	fmt.Printf("%v %v %v\n", v, x, y)
	fmt.Printf("%v\n", result)
}

Unfortunately, testing with or without a WOW64 system displays the same in stdout:

&{0x10ada110 IsWow64Process 2088961457}
0 7 The handle is invalid.
0

What do I do wrong? How to achieve a test to determine if our 32-bit Go program runs on an emulated 32-bit on a 64-bit CPU (WOW64) or on a real 32-bit Windows?

答案1

得分: 4

我认为问题出在你的proc.Callhandle参数上。IsWow64Process期望的参数是一个HANDLE,而不是一个pid。这就是为什么它指示该句柄无效。

以下的SO问题如何从进程ID获取进程句柄指出你需要调用OpenProcess并传入pid,它会返回句柄。

编辑:GetCurrentProcesssyscall中定义。所以我认为你可以用以下代码替换Getpid的调用:

handle, err := syscall.GetCurrentProcess()
英文:

I believe the issue is the handle parameter on your proc.Call. The expected parameter for IsWow64Process is a HANDLE which is not the same as a pid. Which is why it is indicating that the handle is invalid.

The following SO question How to get process handle from process id indicates that you need to call OpenProcess passsing in the pid and it returns the handle.

EDIT: GetCurrentProcess is defined in syscall. So I think you can replace the Getpid call with the following:

handle, err := syscall.GetCurrentProcess()

答案2

得分: 3

好的,下面是代码的中文翻译:

package main

import (
	"syscall"
	"fmt"
	"unsafe"
)

func main() {
	dll, err := syscall.LoadDLL("kernel32.dll")
	if err != nil {
		fmt.Println("无法加载 kernel32")
		fmt.Println(err)
	}
	defer dll.Release()
	proc, err := dll.FindProc("IsWow64Process")
	if err != nil {
		fmt.Println("未找到 Proc")
		fmt.Println(err)
	}
	fmt.Printf("%v\n", proc)

	handle, err := syscall.GetCurrentProcess()
	if err != nil {
		fmt.Println("未找到 Handle")
		fmt.Println(err)
	}
	fmt.Printf("%v\n", handle)

	var result bool

	v, x, y := proc.Call(uintptr(handle), uintptr(unsafe.Pointer(&result)))

	fmt.Printf("%v %v %v\n", v, x, y)
	fmt.Printf("%v\n", result)
}

result 变量在 WOW64 系统上为 true,在 32 位系统上为 false。

英文:

OK, so here is a working code:

package main

import (
	"syscall"
	"fmt"
	"unsafe"
)
func main() {
	dll, err := syscall.LoadDLL("kernel32.dll")
	if err != nil {
		fmt.Println("Can't load kernel32")
		fmt.Println(err)
	}
	defer dll.Release()
	proc, err := dll.FindProc("IsWow64Process")
	if err != nil {
		fmt.Println("Proc not found")
		fmt.Println(err)
	}
	fmt.Printf("%v\n",proc)
	
	handle, err := syscall.GetCurrentProcess()	
	if err != nil {
		fmt.Println("Handle not found")
		fmt.Println(err)
	}
	fmt.Printf("%v\n",handle)
	
	var result bool
	
	v, x, y := proc.Call(uintptr(handle), uintptr(unsafe.Pointer(&result)))

	fmt.Printf("%v %v %v\n",v,x,y)
	fmt.Printf("%v\n",result)
}

The result var will be true for a WOW64 system and false for a 32 bit system.

答案3

得分: 1

你也可以使用golang.org/x/sys/windows

package main

import (
	"fmt"
	"golang.org/x/sys/windows"
)

func main() {
	handle := windows.CurrentProcess()
	var isWow64 bool
	err := windows.IsWow64Process(handle, &isWow64)
	if err != nil {
		panic(err)
	}
	fmt.Println(isWow64)
}
英文:

You can also use golang.org/x/sys/windows

package main

import (
	"fmt"
	"golang.org/x/sys/windows"
)

func main() {
	handle := windows.CurrentProcess()
	var isWow64 bool
	err := windows.IsWow64Process(handle, &isWow64)
	if err != nil {
		panic(err)
	}
	fmt.Println(isWow64)
}

huangapple
  • 本文由 发表于 2015年11月19日 05:32:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/33790814.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定