Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion cmd/extract_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,23 @@ var (
extract = app.Command("extract", "Extract all log messages from all providers.")
extract_file = extract.Arg("file", "File to write all messages").Required().
String()

// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/available-language-packs-for-windows
extract_lang = extract.Flag("lang", "A preferred language for messages (e.g. jp)").String()
)

// Walk over all the providers in the registry and call the callback
// with potential message files. The message_table paths are not
// guaranteed to exists.
func walkProvider(cb func(provider string, message_table string) error) error {
resolver := evtx.NewWindowsMessageResolver()
resolver, err := evtx.NewWindowsMessageResolver(
evtx.MessageResolverOpts{
LangPreferenceRegeExp: *extract_lang,
})
if err != nil {
return err
}

channels_key, err := registry.OpenKey(registry.LOCAL_MACHINE,
`SYSTEM\CurrentControlSet\Services\EventLog`,
registry.READ|registry.ENUMERATE_SUB_KEYS|registry.WOW64_64KEY)
Expand Down
7 changes: 6 additions & 1 deletion cmd/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ var (
Default("99999999").Int()

event_id_filter = parse.Flag("event_id", "Only show these event IDs").Int()

// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/available-language-packs-for-windows
parse_lang = parse.Flag("lang", "A preferred language for messages (e.g. ja-jp (default is en-US ) )").String()
)

type parsingContext struct {
Expand Down Expand Up @@ -92,7 +95,9 @@ func NewParsingContext() *parsingContext {
}

// Otherwise use the native resolver
resolver, err := evtx.GetNativeResolver()
resolver, err := evtx.GetNativeResolver(evtx.MessageResolverOpts{
LangPreferenceRegeExp: *parse_lang,
})
kingpin.FatalIfError(err, " %v", err)

return &parsingContext{resolver}
Expand Down
10 changes: 9 additions & 1 deletion debug.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package evtx

import "fmt"
import (
"encoding/json"
"fmt"
)

const (
debug_enabled = false
Expand All @@ -13,3 +16,8 @@ func debug(format string, args ...interface{}) {
}

func DlvBreak() {}

func Dump(x interface{}) {
serialized, _ := json.MarshalIndent(x, " ", " ")
fmt.Println(string(serialized))
}
135 changes: 48 additions & 87 deletions evtx.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package evtx
import (
"bytes"
"encoding/binary"
"math"
"strings"
"time"

Expand Down Expand Up @@ -364,7 +365,7 @@ func NewParseContext(chunk *Chunk) *ParseContext {
}

func (self *ParseContext) ConsumeUint8() uint8 {
if len(self.buff) < self.offset+1 {
if self.offset > len(self.buff) {
return 0
}
result := self.buff[self.offset]
Expand All @@ -373,31 +374,34 @@ func (self *ParseContext) ConsumeUint8() uint8 {
}

func (self *ParseContext) ConsumeUint16() uint16 {
if len(self.buff) < self.offset+2 {
if self.offset+2 > len(self.buff) {
return 0
}

result := binary.LittleEndian.Uint16(self.buff[self.offset:])
result := binary.LittleEndian.Uint16(
self.buff[self.offset : self.offset+2])
self.offset += 2
return result
}

func (self *ParseContext) ConsumeUint32() uint32 {
if len(self.buff) < self.offset+4 {
if self.offset+4 > len(self.buff) {
return 0
}

result := binary.LittleEndian.Uint32(self.buff[self.offset:])
result := binary.LittleEndian.Uint32(
self.buff[self.offset : self.offset+4])
self.offset += 4
return result
}

func (self *ParseContext) ConsumeUint64() uint64 {
if len(self.buff) < self.offset+8 {
if self.offset+8 > len(self.buff) {
return 0
}

result := binary.LittleEndian.Uint64(self.buff[self.offset:])
result := binary.LittleEndian.Uint64(
self.buff[self.offset : self.offset+8])
self.offset += 8
return result
}
Expand All @@ -413,70 +417,56 @@ func (self *ParseContext) ConsumeBytes(size int) []byte {
}

func (self *ParseContext) ConsumeInt64() (ret int64) {

if len(self.buff) < self.offset+8 {
if self.offset+8 > len(self.buff) {
return 0
}

buf := bytes.NewReader(self.buff[self.offset:])
err := binary.Read(buf, binary.LittleEndian, &ret)
if err != nil {
return 0
}
ret = int64(binary.LittleEndian.Uint64(
self.buff[self.offset : self.offset+8]))
self.offset += 8
return
return ret

}

func (self *ParseContext) ConsumeInt32() (ret int32) {

if len(self.buff) < self.offset+4 {
if self.offset+4 > len(self.buff) {
return 0
}

buf := bytes.NewReader(self.buff[self.offset:])
err := binary.Read(buf, binary.LittleEndian, &ret)
if err != nil {
return 0
}
ret = int32(binary.LittleEndian.Uint32(
self.buff[self.offset : self.offset+4]))
self.offset += 4
return

return ret
}

func (self *ParseContext) ConsumeReal32() (ret float32) {

if len(self.buff) < self.offset+4 {
return 0
}

buf := bytes.NewReader(self.buff[self.offset:])
err := binary.Read(buf, binary.LittleEndian, &ret)
if err != nil {
if self.offset+4 > len(self.buff) {
return 0
}
ret = math.Float32frombits(
binary.LittleEndian.Uint32(self.buff[self.offset : self.offset+4]))
self.offset += 4
return
return ret
}

func (self *ParseContext) ConsumeReal64() (ret float64) {

if len(self.buff) < self.offset+8 {
if self.offset+8 > len(self.buff) {
return 0
}

buf := bytes.NewReader(self.buff[self.offset:])
err := binary.Read(buf, binary.LittleEndian, &ret)
if err != nil {
return 0
}
ret = math.Float64frombits(
binary.LittleEndian.Uint64(self.buff[self.offset : self.offset+8]))

self.offset += 8
return
return ret
}

func (self *ParseContext) ConsumeSysTime(size int) string {

if len(self.buff) < self.offset+16 {
if self.offset+16 > len(self.buff) {
return "SysTimeParsingError"
}

Expand All @@ -491,81 +481,52 @@ func (self *ParseContext) ConsumeSysTime(size int) string {
sec := binary.LittleEndian.Uint16(buffer[12:14])
msec := binary.LittleEndian.Uint16(buffer[14:16])

result := time.Date(int(year), time.Month(month), int(day), int(hour), int(min), int(sec), int(msec), time.UTC)
result := time.Date(int(year), time.Month(month),
int(day), int(hour), int(min), int(sec), int(msec), time.UTC)
return result.String()
}

func (self *ParseContext) ConsumeUnit16Array(size int) []uint16 {

uint16array := []uint16{}
if self.offset+size >= len(self.buff) {
size = len(self.buff) - self.offset - 1
}
if self.offset > len(self.buff) {
return nil
}

buffer := self.buff[self.offset : self.offset+size]
self.offset += size

index := 0
for index < len(buffer) {
value := binary.LittleEndian.Uint16((buffer[index:]))
index := self.offset
for index+2 < len(self.buff) {
value := binary.LittleEndian.Uint16((self.buff[index : index+2]))
uint16array = append(uint16array, value)
index += 2

}

// Still advance the offset as required to maintain alignment.
self.offset += size

return uint16array
}

func (self *ParseContext) ConsumeUnit64Array(size int) []uint64 {

uint64array := []uint64{}
if self.offset+size >= len(self.buff) {
size = len(self.buff) - self.offset - 1
}
if self.offset > len(self.buff) {
return nil
index := self.offset
for index+8 < len(self.buff) {
value := binary.LittleEndian.Uint64((self.buff[index : index+8]))
uint64array = append(uint64array, value)
index += 8
}

buffer := self.buff[self.offset : self.offset+size]
self.offset += size

index := 0
for index < len(buffer) {
value := binary.LittleEndian.Uint64((buffer[index:]))
uint64array = append(uint64array, value)
index += 8

}
return uint64array
}

func (self *ParseContext) ConsumeInt64hexArray(size int) []string {
if self.offset+size >= len(self.buff) {
size = len(self.buff) - self.offset - 1
}
result := []string{}

if self.offset > len(self.buff) {
return nil
index := self.offset
for index+8 < len(self.buff) {
value := binary.LittleEndian.Uint64((self.buff[index : index+8]))
result = append(result, "0x"+fmt.Sprintf("%x", value))
index += 8
}

buffer := self.buff[self.offset : self.offset+size]
self.offset += size
result := []string{}

for i := 0; i < len(buffer); i = i + 8 {

var ret int64
buf := bytes.NewReader(buffer[i : i+8])
err := binary.Read(buf, binary.LittleEndian, &ret)
if err != nil {
return result
}
result = append(result, "0x"+fmt.Sprintf("%x", ret))

}
return result
}

Expand Down
8 changes: 8 additions & 0 deletions message_sets.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ func (self *MessageSet) AddMessage(
number_of_expansions := self.getLargestExpansion(message)
key := event_id<<16 | number_of_expansions

// Only add the message if we do not already have it. This means
// messages n files earlies in the search sequence will be found
// instead of files later.
_, pres := self.Messages[key]
if pres {
return
}

self.Messages[key] = message
self.Filenames[filename] = 1
}
Expand Down
14 changes: 10 additions & 4 deletions messages_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ var (
mui_debug = 0
)

func NewWindowsMessageResolver() *WindowsMessageResolver {
cache, err := lru.New(100)
func NewWindowsMessageResolver(
opts MessageResolverOpts) (*WindowsMessageResolver, error) {
lru_size := opts.LRUSize
if lru_size <= 0 {
lru_size = 100
}

cache, err := lru.New(lru_size)
if err != nil {
panic(err)
return nil, err
}
res := &WindowsMessageResolver{
// string->MessageSet
Expand All @@ -41,7 +47,7 @@ func NewWindowsMessageResolver() *WindowsMessageResolver {

res.buildMUIcache()

return res
return res, res.sortMRUWithRegexp(opts.LangPreferenceRegeExp)
}

type WindowsMessageResolver struct {
Expand Down
13 changes: 13 additions & 0 deletions opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package evtx

type MessageResolverOpts struct {
// A regular expression that if matched, will place the language
// first in the list of languages.
// This defaults to "en-(US|AU|GB)"

// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/available-language-packs-for-windows?view=windows-11
LangPreferenceRegeExp string

// Size of Message LRU - defaults to 100
LRUSize int
}
Loading
Loading