Read window logs in Golang
Last active
July 27, 2023 14:52
-
-
Save will7200/3b2d2aa3bee96b76e9305b4f03136f92 to your computer and use it in GitHub Desktop.
Read Windows Logs in Golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; /* -------------------------------------------------------- | |
; 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 | |
. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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