Skip to content

Instantly share code, notes, and snippets.

@will7200
Last active July 27, 2023 14:52
Show Gist options
  • Save will7200/3b2d2aa3bee96b76e9305b4f03136f92 to your computer and use it in GitHub Desktop.
Save will7200/3b2d2aa3bee96b76e9305b4f03136f92 to your computer and use it in GitHub Desktop.
Read Windows Logs in Golang

Read window logs in Golang

; /* --------------------------------------------------------
; HEADER SECTION
;*/
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR
)
;
;
FacilityNames=(System=0x0:FACILITY_SYSTEM
Runtime=0x2:FACILITY_RUNTIME
Stubs=0x3:FACILITY_STUBS
Io=0x4:FACILITY_IO_ERROR_CODE
)
;
;/* ------------------------------------------------------------------
; MESSAGE DEFINITION SECTION
;*/
MessageIdTypedef=WORD
MessageId=0x1
SymbolicName=CAT_1
Language=English
Category 1
.
MessageId=0x2
SymbolicName=CAT_2
Language=English
Category 2
.
MessageId=0x3
SymbolicName=CAT_3
Language=English
Category 3
.
package main
import (
"fmt"
"os"
"path/filepath"
colorable "github.com/mattn/go-colorable"
log "github.com/sirupsen/logrus"
. "github.com/will7200/go-windowsEventLogs"
"golang.org/x/sys/windows/registry"
"golang.org/x/sys/windows/svc/eventlog"
)
const (
source = "testProgram"
addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
)
func init() {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.TextFormatter{ForceColors: true})
log.SetOutput(colorable.NewColorableStdout())
pwd, _ := os.Getwd()
eventSourceFile := filepath.Join(pwd, "ExampleMessageFile.txt")
exists := checkIfExists()
if !exists {
err := eventlog.Install(source, eventSourceFile, true, 4)
if err != nil {
log.Fatal(err)
}
}
//eventlog.Remove(source)
}
func checkIfExists() bool {
addKey := fmt.Sprintf(`%s\%s`, addKeyName, source)
log.Infof("Looking for %s", addKey)
appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKey, registry.QUERY_VALUE)
if err != nil {
log.Debug(err)
return false
}
t, _ := appkey.ReadValueNames(10)
log.Debug(t)
_, _, err = appkey.GetIntegerValue("CustomSource")
if err != nil {
log.Debug(err)
}
return true
//log.Infof("Key found %d", s)
}
func main() {
log.Info("Installed Correctly")
t, e := eventlog.Open(source)
if e != nil {
log.Fatal(e)
}
t.Info(1, "TESTING FROM SOURCE")
tt, ee := OpenEventLog(source)
if ee != nil {
log.Fatal(e)
}
tt.SetReadFlags(EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ)
tt.ReadEventLog(0, 1000)
tt.Print(0, 1000)
err := tt.Close()
if err != nil {
log.Debug(err)
}
}
package windowseventlogs
import (
"errors"
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
EVENTLOG_SEQUENTIAL_READ = 0x0001
EVENTLOG_SEEK_READ = 0x0002
EVENTLOG_FORWARDS_READ = 0x0004
EVENTLOG_BACKWARDS_READ = 0x0008
MAX_BUFFER_SIZE = 0x7ffff
MAX_DEFAULT_BUFFER_SIZE = 0x10000
)
var (
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procOpenEventLog = modadvapi32.NewProc("OpenEventLogW")
procReadEventLog = modadvapi32.NewProc("ReadEventLogW")
procCloseEventLog = modadvapi32.NewProc("CloseEventLog")
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
func openEventLog(uncServerName *uint16, sourceName *uint16) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall(procOpenEventLog.Addr(), 2, uintptr(unsafe.Pointer(uncServerName)), uintptr(unsafe.Pointer(sourceName)), 0)
handle = windows.Handle(r0)
if handle == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func closeEventLog(log windows.Handle) (err error) {
r0, _, e1 := syscall.Syscall(procCloseEventLog.Addr(), 1, uintptr(log), 0, 0)
if r0 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
func readEventLog(log windows.Handle, readFlags uint32, recordOffset uint32, buffer *byte, bufferSize uint32, bytesRead *uint32, minBytesToRead *uint32) (err error) {
r0, _, e1 := syscall.Syscall9(procReadEventLog.Addr(), 7, uintptr(log), uintptr(readFlags), uintptr(recordOffset), uintptr(unsafe.Pointer(buffer)), uintptr(bufferSize), uintptr(unsafe.Pointer(bytesRead)), uintptr(unsafe.Pointer(minBytesToRead)), 0, 0)
if r0 == 0 {
if e1 != 0 {
err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
}
return
}
// Log provides access to the system log.
type EventLog struct {
Handle windows.Handle
bufferSize uint32
buffer []byte
readFlags uint32
minRead uint32
}
// OpenEventLog retrieves a handle to the specified event log.
func OpenEventLog(source string) (*EventLog, error) {
return OpenRemoteEventLog("", source)
}
// OpenRemoteEventLog does the same as Open, but on different computer host.
func OpenRemoteEventLog(host, source string) (*EventLog, error) {
if source == "" {
return nil, errors.New("Specify event log source")
}
var s *uint16
if host != "" {
s = syscall.StringToUTF16Ptr(host)
}
h, err := openEventLog(s, syscall.StringToUTF16Ptr(source))
if err != nil {
return nil, err
}
buf := make([]byte, MAX_BUFFER_SIZE+1)
return &EventLog{Handle: h, bufferSize: uint32(MAX_DEFAULT_BUFFER_SIZE), buffer: buf, minRead: uint32(0)}, nil
}
// SetBufferSize Sets the buffer size and reallocates the buffer
func (el *EventLog) SetBufferSize(size uint32) bool {
if size <= uint32(MAX_BUFFER_SIZE) {
el.bufferSize = size
buf := make([]byte, size+1)
el.buffer = buf
return true
}
return false
}
// SetReadFlags Sets the Read Flags for Next Reading
func (el *EventLog) SetReadFlags(flags int) bool {
el.readFlags = uint32(flags)
return true
}
// ReadEventLog Calls Windows API to read from log
func (el *EventLog) ReadEventLog(offset uint32, read uint32) {
readEventLog(el.Handle, el.readFlags, offset, &el.buffer[0], el.bufferSize, &read, &el.minRead)
}
// Print from local buffer
func (el *EventLog) Print(offset int, read int) {
for i := 0; i < read; i++ {
if uint32(offset+i) > el.bufferSize {
break
}
fmt.Printf("%c", el.buffer[offset+i])
}
}
// Close the Log Handle
func (el *EventLog) Close() error {
err := closeEventLog(el.Handle)
if err != nil {
return err
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment