-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathqueryobject.go
77 lines (68 loc) · 2.31 KB
/
queryobject.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package handle
// #include "queryobject.h"
import "C"
import (
"errors"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
type objectTypeInformation struct {
TypeName windows.NTUnicodeString
_ [22]uint64 // unused
}
type objectNameInformation struct {
Name windows.NTUnicodeString
}
const (
nameInformationClass = iota + 1
typeInformationClass
)
// ntQueryObject wraps NtQueryObject and supports a timeout logic.
// Because NtQueryObject can deadlock on specific handles, we do
// not want to call it directly. We also can't call it in a separate
// go routine because then that go routine might be permanently blocked.
//
// Instead, we use a native ntQueryThread that starts queryObjects and
// communicate with it via a CGO struct. If the response pipe times
// out, we assume a deadlock and kill the native ntQueryThread.
func (i *Inspector) ntQueryObject(h windows.Handle, informationClass int) (string, error) {
if i.ntQueryThread.IsZero() {
if err := windows.ResetEvent(windows.Handle(i.nativeExchange.ini)); err != nil {
return "", err
}
if err := windows.ResetEvent(windows.Handle(i.nativeExchange.done)); err != nil {
return "", err
}
var err error
i.ntQueryThread, err = createNativeThread(uintptr(C.queryObjects), uintptr(unsafe.Pointer(i.nativeExchange)))
if err != nil {
return "", err
}
}
i.nativeExchange.handle = C.uintptr_t(h)
i.nativeExchange.informationClass = C.int(informationClass)
if err := windows.SetEvent(windows.Handle(i.nativeExchange.ini)); err != nil {
return "", err
}
if s, err := windows.WaitForSingleObject(windows.Handle(i.nativeExchange.done), uint32(i.timeout/time.Millisecond)); s == uint32(windows.WAIT_TIMEOUT) || err != nil {
i.ntQueryThread.Terminate()
i.ntQueryThread = nativeThread{}
return "", ErrTimeout
}
if i.nativeExchange.result != 0 {
return "", windows.NTStatus(i.nativeExchange.result)
}
var str windows.NTUnicodeString
if informationClass == nameInformationClass {
str = (*objectNameInformation)(unsafe.Pointer(&i.nativeExchange.buffer)).Name
} else if informationClass == typeInformationClass {
str = (*objectTypeInformation)(unsafe.Pointer(&i.nativeExchange.buffer)).TypeName
} else {
panic(informationClass)
}
if str.Buffer == nil {
return "", errors.New("NTQueryObject returned nil pointer")
}
return str.String(), nil
}