在C代码中传递带有指向Go内存的指针的结构体。

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

Pass structure with pointers to go memory in C code

问题

我相对于Go语言还比较新,正在学习如何操作本地API。这里有一个具体的例子,需要验证二进制文件是否已签名。为此,我想使用WinVerifyTrust Windows API。

问题是:
WinVerifyTrust提供了一个包含指向WINTRUST_FILE_INFO的指针的WINTRUST_DATA结构,而WINTRUST_FILE_INFO又包含了一个指向字符串的指针 =)

我们知道,在C或syscall中,禁止传递指向包含指向其他go内存的指针的内存的指针。

但我只是需要这样做。需要做些什么呢?

这里有一个包装上述函数的包:https://github.com/itchio/ox/blob/master/winox/verifytrust_windows.go,它们以一种被禁止的方式进行操作

winTrustData.FileOrCatalogOrBlobOrSgnrOrCert = uintptr(unsafe.Pointer(fileData))

trustErr := syscallex.WinVerifyTrust(syscall.Handle(0), &policyGUID, winTrustData)

在传递给syscall之前,不允许将uintptr存储到go对象的中间变量中

我想要做的是:

winTrustFileInfoMemory := C.malloc(unsafe.Sizeof(windows.WinTrustFileInfo{}))
if winTrustFileInfoMemory == nil {
	return errors.New("out of memory")
}
defer C.free(winTrustFileInfoMemory)

winTrustFileInfo := (*windows.WinTrustFileInfo)(unsafe.Pointer(winTrustFileInfoMemory))
winTrustFileInfo.Size = uint32(unsafe.Sizeof(windows.WinTrustFileInfo{}))
....
winTrustData.FileOrCatalogOrBlobOrSgnrOrCert = unsafe.Pointer(winTrustFileInfoMemory)

但这看起来真的很丑陋,我们有没有办法可以固定内存或类似的方法?

英文:

I'm relatively new in Go and studying how to operate with native API. Here is a particular example, need to verify that binary file is signed. For that, I want to use WinVerifyTrust windows API.

The problem:
WinVerifyTrust supplies WINTRUST_DATA structure which contains a pointer to WINTRUST_FILE_INFO which in order contains a pointer to a string =)

As we know it is forbidden to pass a pointer to the memory which contains pointers to other go memory in C or syscall.

But I just need to do that. What needs to be done?

Here is a package which wraps function above https://github.com/itchio/ox/blob/master/winox/verifytrust_windows.go they do that in a forbidden way

winTrustData.FileOrCatalogOrBlobOrSgnrOrCert = uintptr(unsafe.Pointer(fileData))

trustErr := syscallex.WinVerifyTrust(syscall.Handle(0), &policyGUID, winTrustData)

it is not allowed to store uintptr to go object in the intermediate variable before passing to syscall

What I want to do os next:

winTrustFileInfoMemory := C.malloc(unsafe.Sizeof(windows.WinTrustFileInfo{}))
if winTrustFileInfoMemory == nil {
	return errors.New("out of memory")
}
defer C.free(winTrustFileInfoMemory)

winTrustFileInfo := (*windows.WinTrustFileInfo)(unsafe.Pointer(winTrustFileInfoMemory))
winTrustFileInfo.Size = uint32(unsafe.Sizeof(windows.WinTrustFileInfo{}))
....
winTrustData.FileOrCatalogOrBlobOrSgnrOrCert = unsafe.Pointer(winTrustFileInfoMemory)

but it looks really ugly, do we have an ability to somehow pin the memory or something like it?

答案1

得分: 0

根据系统调用文档

> 已弃用:此包已被锁定。调用者应改为使用 golang.org/x/sys 存储库中的相应包。

在你的情况下,相应的函数将是:

func WinVerifyTrustEx(hwnd HWND, actionId *GUID, data *WinTrustData) (ret error)

请注意函数名中的后缀“Ex”。在内部,它调用:

r0, _, _ := syscall.Syscall(procWinVerifyTrustEx.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data)))

所以实际上,现在是由sys/windows而不是你来打破指针规则。很抱歉没有更好的想法。
在此处查看更多信息

英文:

Per the syscall docs:

> Deprecated: this package is locked down. Callers should use the
> corresponding package in the golang.org/x/sys repository instead.

In your case, the corresponding function would be

func WinVerifyTrustEx(hwnd HWND, actionId *GUID, data *WinTrustData) (ret error)

Note the trailing "Ex" in the function name. Internally, this calls:

r0, _, _ := syscall.Syscall(procWinVerifyTrustEx.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data)))

So really, the pointer rule is now being broken by sys/windows instead of you. Sorry there's no better idea.
see here for more.

huangapple
  • 本文由 发表于 2022年8月25日 18:48:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/73486193.html
匿名

发表评论

匿名网友

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

确定