Skip to content

Instantly share code, notes, and snippets.

@henkman
Created February 2, 2018 10:58
Show Gist options
  • Select an option

  • Save henkman/70dac0b78ac41fc689ec8c5b4c689ea9 to your computer and use it in GitHub Desktop.

Select an option

Save henkman/70dac0b78ac41fc689ec8c5b4c689ea9 to your computer and use it in GitHub Desktop.
package main
import (
"encoding/binary"
"errors"
"flag"
"fmt"
"syscall"
"time"
"unsafe"
)
type Uptime struct {
Start time.Time
End time.Time
}
type EVENTLOGRECORD struct {
Length uint32
Reserved uint32
RecordNumber uint32
TimeGenerated uint32
TimeWritten uint32
EventID uint32
EventType uint16
NumStrings uint16
EventCategory uint16
ReservedFlags uint16
ClosingRecordNumber uint32
StringOffset uint32
UserSidLength uint32
UserSidOffset uint32
DataLength uint32
DataOffset uint32
}
type HANDLE uintptr
const (
EVENTLOG_SEQUENTIAL_READ = 0x0002
EVENTLOG_BACKWARDS_READ = 0x0008
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
getLastError = kernel32.NewProc("GetLastError")
advapi32 = syscall.NewLazyDLL("advapi32.dll")
openEventLog = advapi32.NewProc("OpenEventLogW")
readEventLog = advapi32.NewProc("ReadEventLogW")
closeEventLog = advapi32.NewProc("CloseEventLog")
)
func GetLastError() uint32 {
ret, _, _ := getLastError.Call()
return uint32(ret)
}
func OpenEventLog(servername string, sourcename string) HANDLE {
ret, _, _ := openEventLog.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(servername))),
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(sourcename))))
return HANDLE(ret)
}
func ReadEventLog(eventlog HANDLE, readflags, recordoffset uint32, buffer []byte, numberofbytestoread uint32, bytesread, minnumberofbytesneeded *uint32) bool {
ret, _, _ := readEventLog.Call(
uintptr(eventlog),
uintptr(readflags),
uintptr(recordoffset),
uintptr(unsafe.Pointer(&buffer[0])),
uintptr(numberofbytestoread),
uintptr(unsafe.Pointer(bytesread)),
uintptr(unsafe.Pointer(minnumberofbytesneeded)))
fmt.Println("ERROR:", ret, GetLastError())
return ret != 0
}
func CloseEventLog(eventlog HANDLE) bool {
ret, _, _ := closeEventLog.Call(
uintptr(eventlog))
return ret != 0
}
type Bytes []byte
func (this Bytes) Read(p []byte) (int, error) {
n := copy(p, this[0:len(p)])
this = this[n:]
return n, nil
}
const (
EVENT_ID_SHUTDOWN = 6006
EVENT_ID_STARTUP = 6009
)
func GetUptimes(n uint) ([]Uptime, error) {
log := OpenEventLog("", "system")
if log == 0 {
return nil, errors.New("could not open event log")
}
up := Uptime{End: time.Now()}
var read, req, offset uint32
var record EVENTLOGRECORD
recordsize := uint32(unsafe.Sizeof(record))
uptimes := []Uptime{}
buf := make([]byte, 0x7ffff)
for ReadEventLog(log, EVENTLOG_BACKWARDS_READ|EVENTLOG_SEQUENTIAL_READ, 0, buf, uint32(len(buf)), &read, &req) {
fmt.Println(read, req)
offset = 0
for offset < read {
in := Bytes(buf[offset : offset+recordsize])
err := binary.Read(in, binary.LittleEndian, &record)
if err != nil {
CloseEventLog(log)
return nil, err
}
eventid := record.EventID & 0xFFFF
tm := time.Unix(int64(record.TimeGenerated), 0)
if eventid == EVENT_ID_STARTUP {
up.Start = tm
uptimes = append(uptimes, up)
} else if eventid == EVENT_ID_SHUTDOWN {
up.End = tm
}
offset += record.Length
}
}
CloseEventLog(log)
return uptimes, nil
}
func main() {
var opts struct {
N uint
}
flag.UintVar(&opts.N, "n", 0, "number of elements to show")
flag.Parse()
if uptimes, err := GetUptimes(opts.N); err != nil {
for _, uptime := range uptimes {
fmt.Println(uptime)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment