gpt4 book ai didi

winapi - 使用 go 读取 ETW 提供程序

转载 作者:IT王子 更新时间:2023-10-29 02:09:53 27 4
gpt4 key购买 nike

我正在尝试从 Advapi32.dll 中访问 EnumerateTraceGuids 函数。我还处于非常早期的阶段,仍在尝试破译我必须做什么。我有以下代码不断给我错误:87,意思是 ERROR_INVALID_PARAMETER。

虽然它只是写入而不是读取,但我已将此文件用作起点: https://github.com/moby/moby/blob/master/daemon/logger/etwlogs/etwlogs_windows.go

我要调用的函数的官方文档在这里: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363713(v=vs.85).aspx

它需要 GuidPropertiesArray [in, out] 指向 TRACE_GUID_PROPERTIES 结构的指针数组。此结构如下 ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa364143(v=vs.85).aspx )

typedef struct _TRACE_GUID_PROPERTIES {
GUID Guid;
ULONG GuidType;
ULONG LoggerId;
ULONG EnableLevel;
ULONG EnableFlags;
BOOLEAN IsEnable;
} TRACE_GUID_PROPERTIES, *PTRACE_GUID_PROPERTIES;

我有以下代码来尝试执行此操作:

package main
import (
"errors"
"fmt"
"syscall"
"unsafe"
"github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
)

const (
win32CallSuccess = 0
MaxProv = 50
nbProviders = 50
)

var (
modAdvapi32 = windows.NewLazySystemDLL("Advapi32.dll")
procEnumerateTraceGuids = modAdvapi32.NewProc("EnumerateTraceGuids")
)

type ulong int32

type TRACE_GUID_PROPERTIES struct {
Guid syscall.GUID
GuidType ulong
LoggerId ulong
EnableLevel ulong
EnableFlags ulong
IsEnable bool
}

func callEnumerateTraceGuids() error {
GuidPropertiesArray:= make([]TRACE_GUID_PROPERTIES, 1)
ptr := &GuidPropertiesArray[0]
ret, _, _ := procEnumerateTraceGuids.Call(uintptr(unsafe.Pointer(&ptr)), MaxProv, nbProviders)
if ret != win32CallSuccess {
errorMessage := fmt.Sprintf("Failed to register ETW provider. Error: %d", ret)
logrus.Error(errorMessage)
return errors.New(errorMessage)
}
return nil
}

func main() {
callEnumerateTraceGuids()
}

此时我不确定我必须做什么。我尝试了很多初始化数组的变体,但都没有成功。希望有人能指出我正确的方向。谢谢!

编辑:根据评论更改了代码,但仍然出现相同的错误。

PS:这是我第一次在 stackoverflow 上发帖,我已经被告知我在发布问题后不到 12 小时就懒惰了(耶!)所以不确定我问的是否正确...我我不太熟悉 go 并且之前从未从 go 调用过 Windows DLL,因为我一直在点击那个 ERROR_INVALID_PARAMETER 我想伸出手去尝试通过这第一堵墙以便能够同时掌握一些概念。希望这有助于理解我的请求(即,我平安而来)。

最佳答案

好吧,我有一点空闲时间并且可以使用 Windows XP 盒子,所以我决定重温我的 Windows 编程技能并编写了一个可行的解决方案:

package main

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

"log"
"syscall"
"unsafe"
)

var (
modAdvapi32 = windows.NewLazySystemDLL("advapi32")
procEnumerateTraceGuids = modAdvapi32.NewProc("EnumerateTraceGuids")
)

type traceGuidProperties struct {
guid syscall.GUID
guidType uint32
loggerId uint32
enableLevel uint32
enableFlags uint32
isEnable uint32
}

func enumerateTraceGuids(ptr **traceGuidProperties, count uint32, out *uint32) error {
rc, _, _ := procEnumerateTraceGuids.Call(uintptr(unsafe.Pointer(ptr)),
uintptr(count), uintptr(unsafe.Pointer(out)))
if rc != 0 {
return syscall.Errno(rc)
}
return nil
}

func enumTraceGuids() ([]*traceGuidProperties, error) {
var errMoreData = syscall.Errno(234)

var (
dummyProps traceGuidProperties
dummyPtr = &dummyProps

count uint32
)

err := enumerateTraceGuids(&dummyPtr, 0, &count)
if err != errMoreData {
return nil, err
}

items := make([]*traceGuidProperties, count)
for i := range items {
items[i] = new(traceGuidProperties)
}

for {
err = enumerateTraceGuids(&items[0], count, &count)
if err == nil {
break
}
if err != errMoreData {
return nil, err
}
for i := 0; i < int(count)-len(items); i++ {
items = append(items, new(traceGuidProperties))
}
}

return items[:count], nil
}

func main() {
log.SetFlags(0)

data, err := enumTraceGuids()
if err != nil {
log.Fatal(err)
}
log.Printf("len(data)=%d\n", len(data))
for i := range data {
log.Println(*(data[i]))
}
}

要点:

  • 我告诉你的时候我错了«你……应该分配一个结构数组(而不是指针)»——事实上EnumerateTraceGuids 确实需要一个指针数组。

  • 如提示here ,EnumerateTraceGuids 的工作方式有两个微妙之处:

    • 与其文档所述相反,它实际上支持用它的 PropertyArrayCount 调用参数设置为 0,在这种情况下,它应该返回 ERROR_MORE_DATA同时将 GuidCount 设置为输入的元素数(下一次)调用成功完成所需的数组。IOW,这样我们就知道系统当前有多少跟踪 GUID“知道”。
    • 尽管如此,即使在这种情况下,函数也会执行有效性检查在输入数组上(见下文)。
  • 事实证明,该函数需要一个指向的指针数组TRACE_GUID_PROPERTIES block 由您分配。

    换句话说,如果它说你知道大约 10 个跟踪 GUID,您必须分配 10 个 TRACE_GUID_PROPERTIES 类型的值,然后创建一个包含 10 个指向这些值的指针的数组并传递一个指针将该数组的第一个元素传递给函数。

  • 请注意,发生的变化之间存在固有的竞争在系统中(由于各种原因添加或删除的痕迹)以及对 EnumerateTraceGuids 的调用。

    这意味着如果第一次调用这个函数告诉你它“知道”大约 10 个跟踪 GUID,在下一次调用时可能会出现已经有 20 个跟踪 GUID,或 5 个 GUID(或任何其他数量的 FWIW)。

    因此我们通过以下方式考虑这两种可能性:

    1. 首先,我们使用指向单个(但有效)的指针进行调用TRACE_GUID_PROPERTIES 值,静态分配(因此函数“看到”看起来像单个元素的数组),在告诉函数输入“数组”有零个元素时。

      我们预计该函数会失败并返回 ERROR_MORE_DATA并将它“知道”的跟踪 GUID 的实际数量放入变量中我们已经为它提供了一个指针。

    2. 我们分配那么多 TRACE_GUID_PROPERTIES 内存块第一次调用时指示的函数。为此,我们使用 new() 内置函数就像标准 C 库中的 malloc()——它为指定类型的值并返回指向分配的指针内存块。

    3. 我们创建一个指向这些已分配内存块的指针数组并再次调用 EnumerateTraceGuids

    4. 如果成功,我们会处理返回较少的可能性比我们分配的元素更多,并重新 slice 我们的 slice 。

    5. 如果它因 ERROR_MORE_DATA 而失败,我们将扩展我们的 slice 无论需要多少元素(为它们分配内存TRACE_GUID_PROPERTIES 首先阻塞),然后尝试再次调用该函数。

  • “魔数(Magic Number)”234 是 ERROR_MORE_DATA 值的实际代码。

对于最初的困惑,我们深表歉意。

关于winapi - 使用 go 读取 ETW 提供程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50124486/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com