Created
February 2, 2018 10:58
-
-
Save henkman/70dac0b78ac41fc689ec8c5b4c689ea9 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 ( | |
| "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