146 lines
4.1 KiB
Go
146 lines
4.1 KiB
Go
package syscall
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"github.com/amidaware/rmmagent/agent/utils"
|
|
"github.com/gonutz/w32/v2"
|
|
"golang.org/x/sys/windows"
|
|
"golang.org/x/sys/windows/registry"
|
|
)
|
|
|
|
type ReadFlag uint32
|
|
|
|
const (
|
|
EVENTLOG_SEQUENTIAL_READ ReadFlag = 1 << iota
|
|
EVENTLOG_SEEK_READ
|
|
EVENTLOG_FORWARDS_READ
|
|
EVENTLOG_BACKWARDS_READ
|
|
)
|
|
|
|
const (
|
|
DONT_RESOLVE_DLL_REFERENCES uint32 = 0x0001
|
|
LOAD_LIBRARY_AS_DATAFILE uint32 = 0x0002
|
|
)
|
|
|
|
var (
|
|
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
|
|
|
procFormatMessageW = modkernel32.NewProc("FormatMessageW")
|
|
procGetOldestEventLogRecord = modadvapi32.NewProc("GetOldestEventLogRecord")
|
|
procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
|
|
procReadEventLogW = modadvapi32.NewProc("ReadEventLogW")
|
|
)
|
|
|
|
func GetOldestEventLogRecord(eventLog w32.HANDLE, oldestRecord *uint32) (err error) {
|
|
r1, _, e1 := syscall.Syscall(procGetOldestEventLogRecord.Addr(), 2, uintptr(eventLog), uintptr(unsafe.Pointer(oldestRecord)), 0)
|
|
if r1 == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func ReadEventLog(eventLog w32.HANDLE, readFlags ReadFlag, recordOffset uint32, buffer *byte, numberOfBytesToRead uint32, bytesRead *uint32, minNumberOfBytesNeeded *uint32) (err error) {
|
|
r1, _, e1 := syscall.Syscall9(procReadEventLogW.Addr(), 7, uintptr(eventLog), uintptr(readFlags), uintptr(recordOffset), uintptr(unsafe.Pointer(buffer)), uintptr(numberOfBytesToRead), uintptr(unsafe.Pointer(bytesRead)), uintptr(unsafe.Pointer(minNumberOfBytesNeeded)), 0, 0)
|
|
if r1 == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func LoadLibraryEx(filename *uint16, file syscall.Handle, flags uint32) (handle syscall.Handle, err error) {
|
|
r0, _, e1 := syscall.Syscall(procLoadLibraryExW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(file), uintptr(flags))
|
|
handle = syscall.Handle(r0)
|
|
if handle == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func FormatMessage(flags uint32, source syscall.Handle, messageID uint32, languageID uint32, buffer *byte, bufferSize uint32, arguments uintptr) (numChars uint32, err error) {
|
|
r0, _, e1 := syscall.Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(source), uintptr(messageID), uintptr(languageID), uintptr(unsafe.Pointer(buffer)), uintptr(bufferSize), uintptr(arguments), 0, 0)
|
|
numChars = uint32(r0)
|
|
if numChars == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// https://github.com/mackerelio/go-check-plugins/blob/ad7910fdc45ccb892b5e5fda65ba0956c2b2885d/check-windows-eventlog/lib/check-windows-eventlog.go#L232
|
|
func GetResourceMessage(providerName, sourceName string, eventID uint32, argsptr uintptr) (string, error) {
|
|
regkey := fmt.Sprintf(
|
|
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s",
|
|
providerName, sourceName)
|
|
key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.QUERY_VALUE)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
defer key.Close()
|
|
val, _, err := key.GetStringValue("EventMessageFile")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
val, err = registry.ExpandString(val)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
handle, err := LoadLibraryEx(syscall.StringToUTF16Ptr(val), 0,
|
|
DONT_RESOLVE_DLL_REFERENCES|LOAD_LIBRARY_AS_DATAFILE)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
defer syscall.CloseHandle(handle)
|
|
|
|
msgbuf := make([]byte, 1<<16)
|
|
numChars, err := FormatMessage(
|
|
syscall.FORMAT_MESSAGE_FROM_SYSTEM|
|
|
syscall.FORMAT_MESSAGE_FROM_HMODULE|
|
|
syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
handle,
|
|
eventID,
|
|
0,
|
|
&msgbuf[0],
|
|
uint32(len(msgbuf)),
|
|
argsptr)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
message, _ := utils.BytesToString(msgbuf[:numChars*2])
|
|
message = strings.Replace(message, "\r", "", -1)
|
|
message = strings.TrimSuffix(message, "\n")
|
|
return message, nil
|
|
}
|
|
|
|
func StringToUTF16Ptr(val string) *uint16 {
|
|
return syscall.StringToUTF16Ptr(val)
|
|
}
|
|
|
|
func CloseHandle(handle syscall.Handle) {
|
|
defer syscall.CloseHandle(handle)
|
|
}
|