Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Winlogbeat] Fixes for wineventlog experimental api #26826

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Protect against accessing undefined variables in Sysmon module. {issue}22219[22219] {pull}22236[22236]
- Protect against accessing an undefined variable in Security module. {pull}22937[22937]
- Fix related.ip field in renameCommonAuthFields {pull}24892[24892]
- Fix an issue with message template caching in the `wineventlog-experimental` API implementation. {pull}26826[26826]

*Functionbeat*

Expand Down
2 changes: 1 addition & 1 deletion winlogbeat/sys/wineventlog/format_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func getMessageString(metadata *PublisherMetadata, eventHandle EvtHandle, messag
var flags EvtFormatMessageFlag
if eventHandle > 0 {
flags = EvtFormatMessageEvent
} else if messageID > 0 {
} else {
flags = EvtFormatMessageId
}

Expand Down
22 changes: 15 additions & 7 deletions winlogbeat/sys/wineventlog/metadata_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ type EventMetadata struct {
Version uint8 // Event format version.
MsgStatic string // Used when the message has no parameters.
MsgTemplate *template.Template `json:"-"` // Template that expects an array of values as its data.
EventData []eventData // Names of parameters from XML template.
EventData []EventData // Names of parameters from XML template.
}

// newEventMetadataFromEventHandle collects metadata about an event type using
Expand All @@ -307,11 +307,11 @@ func newEventMetadataFromEventHandle(publisher *PublisherMetadata, eventHandle E
}
if len(event.EventData.Pairs) > 0 {
for _, pair := range event.EventData.Pairs {
em.EventData = append(em.EventData, eventData{Name: pair.Key})
em.EventData = append(em.EventData, EventData{Name: pair.Key})
}
} else {
for _, pair := range event.UserData.Pairs {
em.EventData = append(em.EventData, eventData{Name: pair.Key})
em.EventData = append(em.EventData, EventData{Name: pair.Key})
}
}

Expand Down Expand Up @@ -396,10 +396,15 @@ func (em *EventMetadata) initEventMessage(itr *EventMetadataIterator, publisher
if err != nil {
return err
}
// If the event definition does not specify a message, the value is –1.
if int32(messageID) == -1 {
return nil
}

msg, err := getMessageString(publisher, NilHandle, messageID, templateInserts.Slice())
if err != nil {
return err
return errors.Wrapf(err, "failed to get message string using message "+
"ID %v for for event ID %v", messageID, em.EventID)
}

return em.setMessage(msg)
Expand All @@ -409,9 +414,12 @@ func (em *EventMetadata) setMessage(msg string) error {
msg = sys.RemoveWindowsLineEndings(msg)
tmplID := strconv.Itoa(int(em.EventID))

tmpl, err := template.New(tmplID).Funcs(eventMessageTemplateFuncs).Parse(msg)
tmpl, err := template.New(tmplID).
Delims(leftTemplateDelim, rightTemplateDelim).
Funcs(eventMessageTemplateFuncs).Parse(msg)
if err != nil {
return err
return errors.Wrapf(err, "failed to parse message template for "+
"event ID %v (template='%v')", em.EventID, msg)
}

// One node means there were no parameters so this will optimize that case
Expand All @@ -432,7 +440,7 @@ func (em *EventMetadata) equal(other *EventMetadata) bool {
return false
}

eventDataNamesEqual := func(a, b []eventData) bool {
eventDataNamesEqual := func(a, b []EventData) bool {
if len(a) != len(b) {
return false
}
Expand Down
8 changes: 6 additions & 2 deletions winlogbeat/sys/wineventlog/stringinserts.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const (
// maxInsertStrings is the maximum number of parameters supported in a
// Windows event message.
maxInsertStrings = 99

leftTemplateDelim = "[{{"
rightTemplateDelim = "}}]"
)

// templateInserts contains EvtVariant values that can be used to substitute
Expand All @@ -45,7 +48,7 @@ type stringInserts struct {
evtVariants [maxInsertStrings]EvtVariant
}

// Pointer returns a pointer the EvtVariant array.
// Slice returns a slice of the full EvtVariant array.
func (si *stringInserts) Slice() []EvtVariant {
return si.evtVariants[:]
}
Expand All @@ -66,7 +69,8 @@ func newTemplateStringInserts() *stringInserts {

for i := 0; i < len(si.evtVariants); i++ {
// Use i+1 to keep our inserts numbered the same as Window's inserts.
strSlice, err := windows.UTF16FromString(`{{eventParam $ ` + strconv.Itoa(i+1) + `}}`)
templateParam := leftTemplateDelim + `eventParam $ ` + strconv.Itoa(i+1) + rightTemplateDelim
strSlice, err := windows.UTF16FromString(templateParam)
if err != nil {
// This will never happen.
panic(err)
Expand Down
2 changes: 2 additions & 0 deletions winlogbeat/sys/wineventlog/syscall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,3 +661,5 @@ func EvtClearLog(session EvtHandle, channelPath string, targetFilePath string) e
//sys _EvtNextEventMetadata(enumerator EvtHandle, flags uint32) (handle EvtHandle, err error) = wevtapi.EvtNextEventMetadata
//sys _EvtGetObjectArrayProperty(objectArray EvtObjectArrayPropertyHandle, propertyID EvtPublisherMetadataPropertyID, arrayIndex uint32, flags uint32, bufferSize uint32, evtVariant *EvtVariant, bufferUsed *uint32) (err error) = wevtapi.EvtGetObjectArrayProperty
//sys _EvtGetObjectArraySize(objectArray EvtObjectArrayPropertyHandle, arraySize *uint32) (err error) = wevtapi.EvtGetObjectArraySize
//sys _EvtOpenPublisherEnum(session EvtHandle, flags uint32) (handle EvtHandle, err error) = wevtapi.EvtOpenPublisherEnum
//sys _EvtNextPublisherId(enumerator EvtHandle, bufferSize uint32, buffer *byte, bufferUsed *uint32) (err error) = wevtapi.EvtNextPublisherId
9 changes: 5 additions & 4 deletions winlogbeat/sys/wineventlog/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import (
)

type eventTemplate struct {
Data []eventData `xml:"data"`
Data []EventData `xml:"data"`
}

type eventData struct {
Name string `xml:"name,attr"`
Type string `xml:"outType,attr"`
type EventData struct {
Name string `xml:"name,attr"`
InType string `xml:"inType,attr"`
OutType string `xml:"outType,attr"`
}

func (t *eventTemplate) Unmarshal(xmlData []byte) error {
Expand Down
41 changes: 41 additions & 0 deletions winlogbeat/sys/wineventlog/wineventlog_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"io"
"reflect"
"runtime"
"sort"
"syscall"

"github.com/elastic/beats/v7/libbeat/common"
Expand Down Expand Up @@ -419,6 +420,46 @@ func FormatEventString(
return common.UTF16ToUTF8Bytes(buffer[:bufferUsed], out)
}

// Publishers returns a sort list of event publishers on the local computer.
func Publishers() ([]string, error) {
publisherEnumerator, err := _EvtOpenPublisherEnum(NilHandle, 0)
if err != nil {
return nil, fmt.Errorf("failed in EvtOpenPublisherEnum: %w", err)
}
defer Close(publisherEnumerator)

var (
publishers []string
bufferUsed uint32
buffer = make([]byte, 1024)
)

loop:
for {
if err = _EvtNextPublisherId(publisherEnumerator, uint32(len(buffer)), &buffer[0], &bufferUsed); err != nil {
adriansr marked this conversation as resolved.
Show resolved Hide resolved
switch err {
case ERROR_NO_MORE_ITEMS:
break loop
case ERROR_INSUFFICIENT_BUFFER:
buffer = make([]byte, 2*bufferUsed)
continue loop
default:
return nil, fmt.Errorf("failed in EvtNextPublisherId: %w", err)
}
}

provider, err := sys.UTF16BytesToString(buffer)
if err != nil {
return nil, err
}

publishers = append(publishers, provider)
}

sort.Strings(publishers)
return publishers, nil
}

// offset reads a pointer value from the reader then calculates an offset from
// the start of the buffer to the pointer location. If the pointer value is
// NULL or is outside of the bounds of the buffer then an error is returned.
Expand Down
12 changes: 12 additions & 0 deletions winlogbeat/sys/wineventlog/wineventlog_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,15 @@ func TestChannels(t *testing.T) {
}
}
}

func TestPublishers(t *testing.T) {
publishers, err := Publishers()
if err != nil {
t.Fatal(err)
}

assert.NotEmpty(t, publishers)
for _, p := range publishers {
t.Log(p)
}
}
21 changes: 19 additions & 2 deletions winlogbeat/sys/wineventlog/zsyscall_windows.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.