Esempio n. 1
0
// parseInsertStrings parses the insert strings from buffer which should contain
// an eventLogRecord. It returns an array of strings (data is copied and
// converted to UTF-8) and an array of pointers to the null-terminated UTF-16
// strings within buffer.
func parseInsertStrings(record eventLogRecord, buffer []byte) ([]string, []uintptr, error) {
	if record.numStrings < 1 {
		return nil, nil, nil
	}

	inserts := make([]string, record.numStrings)
	insertPtrs := make([]uintptr, record.numStrings)
	offset := int(record.stringOffset)
	bufferPtr := reflect.ValueOf(&buffer[0]).Pointer()

	for i := 0; i < int(record.numStrings); i++ {
		if offset > len(buffer) {
			return nil, nil, fmt.Errorf("Failed reading string number %d, "+
				"offset=%d, len(buffer)=%d, record=%+v", i+1, offset,
				len(buffer), record)
		}
		insertStr, length, err := sys.UTF16BytesToString(buffer[offset:])
		if err != nil {
			return nil, nil, err
		}
		inserts[i] = insertStr
		insertPtrs[i] = bufferPtr + uintptr(offset)
		offset += length
	}

	return inserts, insertPtrs, nil
}
Esempio n. 2
0
// readString reads a pointer using the reader then parses the UTF-16 string
// that the pointer addresses within the buffer.
func readString(buffer []byte, reader io.Reader) (string, error) {
	offset, err := offset(buffer, reader)
	if err != nil {
		// Ignore NULL values.
		if err == ErrorEvtVarTypeNull {
			return "", nil
		}
		return "", err
	}
	str, _, err := sys.UTF16BytesToString(buffer[offset:])
	return str, err
}
Esempio n. 3
0
// FormatEventString formats part of the event as a string.
// messageFlag determines what part of the event is formatted as as string.
// eventHandle is the handle to the event.
// publisher is the name of the event's publisher.
// publisherHandle is a handle to the publisher's metadata as provided by
// EvtOpenPublisherMetadata.
// lang is the language ID.
// buffer is optional and if not provided it will be allocated. If the provided
// buffer is not large enough then an InsufficientBufferError will be returned.
func FormatEventString(
	messageFlag EvtFormatMessageFlag,
	eventHandle EvtHandle,
	publisher string,
	publisherHandle EvtHandle,
	lang uint32,
	buffer []byte,
) (string, error) {
	// Open a publisher handle if one was not provided.
	ph := publisherHandle
	if ph == 0 {
		ph, err := OpenPublisherMetadata(0, publisher, 0)
		if err != nil {
			return "", err
		}
		defer _EvtClose(ph)
	}

	// Create a buffer if one was not provider.
	var bufferUsed uint32
	if buffer == nil {
		err := _EvtFormatMessage(ph, eventHandle, 0, 0, 0, messageFlag,
			0, nil, &bufferUsed)
		if err != nil && err != ERROR_INSUFFICIENT_BUFFER {
			return "", err
		}

		bufferUsed *= 2
		buffer = make([]byte, bufferUsed)
		bufferUsed = 0
	}

	err := _EvtFormatMessage(ph, eventHandle, 0, 0, 0, messageFlag,
		uint32(len(buffer)/2), &buffer[0], &bufferUsed)
	bufferUsed *= 2
	if err == ERROR_INSUFFICIENT_BUFFER {
		return "", sys.InsufficientBufferError{err, int(bufferUsed)}
	}
	if err != nil {
		return "", err
	}

	// This assumes there is only a single string value to read. This will
	// not work to read keys (when messageFlag == EvtFormatMessageKeyword).
	value, _, err := sys.UTF16BytesToString(buffer[0:bufferUsed])
	return value, err
}
Esempio n. 4
0
// RenderEventNoMessage render the events as XML but without the RenderingInfo (message).
func RenderEventNoMessage(eventHandle EvtHandle, renderBuf []byte) (string, error) {
	var bufferUsed, propertyCount uint32
	err := _EvtRender(0, eventHandle, EvtRenderEventXml, uint32(len(renderBuf)),
		&renderBuf[0], &bufferUsed, &propertyCount)
	if err == ERROR_INSUFFICIENT_BUFFER {
		return "", sys.InsufficientBufferError{err, int(bufferUsed)}
	}
	if err != nil {
		return "", err
	}

	if int(bufferUsed) > len(renderBuf) {
		return "", fmt.Errorf("Windows EvtRender reported that wrote %d bytes "+
			"to the buffer, but the buffer can only hold %d bytes",
			bufferUsed, len(renderBuf))
	}
	xml, _, err := sys.UTF16BytesToString(renderBuf[:bufferUsed])
	return xml, err
}
Esempio n. 5
0
// parseEventLogRecord parses a single Windows EVENTLOGRECORD struct from the
// buffer.
func parseEventLogRecord(buffer []byte) (eventLogRecord, error) {
	var record eventLogRecord
	reader := bytes.NewReader(buffer)

	// Length
	err := binary.Read(reader, binary.LittleEndian, &record.length)
	if err != nil {
		return record, err
	}
	if len(buffer) < int(record.length) {
		return record, fmt.Errorf("Decoded EVENTLOGRECORD length (%d) is "+
			"greater than the buffer length (%d)", record.length, len(buffer))
	}

	// Reserved
	err = binary.Read(reader, binary.LittleEndian, &record.reserved)
	if err != nil {
		return record, err
	}
	if record.reserved != uint32(0x654c664c) {
		return record, fmt.Errorf("Buffer does not contain ELF_LOG_SIGNATURE. "+
			"The data is invalid. Value is %X", record.reserved)
	}

	// Buffer appears to be value so slice it to the adjust length.
	buffer = buffer[:record.length]
	reader = bytes.NewReader(buffer)
	reader.Seek(8, 0)

	// RecordNumber
	err = binary.Read(reader, binary.LittleEndian, &record.recordNumber)
	if err != nil {
		return record, err
	}

	// TimeGenerated
	err = binary.Read(reader, binary.LittleEndian, &record.timeGenerated)
	if err != nil {
		return record, err
	}

	// TimeWritten
	err = binary.Read(reader, binary.LittleEndian, &record.timeWritten)
	if err != nil {
		return record, err
	}

	// EventID
	err = binary.Read(reader, binary.LittleEndian, &record.eventID)
	if err != nil {
		return record, err
	}

	// EventType
	err = binary.Read(reader, binary.LittleEndian, &record.eventType)
	if err != nil {
		return record, err
	}

	// NumStrings
	err = binary.Read(reader, binary.LittleEndian, &record.numStrings)
	if err != nil {
		return record, err
	}

	// EventCategory
	err = binary.Read(reader, binary.LittleEndian, &record.eventCategory)
	if err != nil {
		return record, err
	}

	// ReservedFlags (2 bytes), ClosingRecordNumber (4 bytes)
	_, err = reader.Seek(6, 1)
	if err != nil {
		return record, err
	}

	// StringOffset
	err = binary.Read(reader, binary.LittleEndian, &record.stringOffset)
	if err != nil {
		return record, err
	}
	if record.numStrings > 0 && record.stringOffset > record.length {
		return record, fmt.Errorf("StringOffset value (%d) is invalid "+
			"because it is greater than the Length (%d)", record.stringOffset,
			record.length)
	}

	// UserSidLength
	err = binary.Read(reader, binary.LittleEndian, &record.userSidLength)
	if err != nil {
		return record, err
	}

	// UserSidOffset
	err = binary.Read(reader, binary.LittleEndian, &record.userSidOffset)
	if err != nil {
		return record, err
	}
	if record.userSidLength > 0 && record.userSidOffset > record.length {
		return record, fmt.Errorf("UserSidOffset value (%d) is invalid "+
			"because it is greater than the Length (%d)", record.userSidOffset,
			record.length)
	}

	// DataLength
	err = binary.Read(reader, binary.LittleEndian, &record.dataLength)
	if err != nil {
		return record, err
	}

	// DataOffset
	err = binary.Read(reader, binary.LittleEndian, &record.dataOffset)
	if err != nil {
		return record, err
	}

	// SourceName (null-terminated UTF-16 string)
	begin, _ := reader.Seek(0, 1)
	sourceName, length, err := sys.UTF16BytesToString(buffer[begin:])
	if err != nil {
		return record, err
	}
	record.sourceName = sourceName
	begin, err = reader.Seek(int64(length), 1)
	if err != nil {
		return record, err
	}

	// ComputerName (null-terminated UTF-16 string)
	computerName, length, err := sys.UTF16BytesToString(buffer[begin:])
	if err != nil {
		return record, err
	}
	record.computerName = computerName
	_, err = reader.Seek(int64(length), 1)
	if err != nil {
		return record, err
	}

	return record, nil
}
Esempio n. 6
0
// formatMessage takes event data and formats the event message into a
// normalized format.
func formatMessage(
	sourceName string,
	eventID uint32,
	lang uint32,
	stringInserts []uintptr,
	buffer []byte,
	pubHandleProvider func(string) sys.MessageFiles,
) (string, error) {
	var addr uintptr
	if len(stringInserts) > 0 {
		addr = reflect.ValueOf(&stringInserts[0]).Pointer()
	}

	messageFiles := pubHandleProvider(sourceName)

	var lastErr error
	var fh sys.FileHandle
	var message string
	for _, fh = range messageFiles.Handles {
		if fh.Err != nil {
			lastErr = fh.Err
			continue
		}

		numChars, err := _FormatMessage(
			windows.FORMAT_MESSAGE_FROM_HMODULE|
				windows.FORMAT_MESSAGE_ARGUMENT_ARRAY,
			Handle(fh.Handle),
			eventID,
			lang,
			&buffer[0],            // Max size allowed is 64k bytes.
			uint32(len(buffer)/2), // Size of buffer in TCHARS
			addr)
		// bufferUsed = numChars * sizeof(TCHAR) + sizeof(null-terminator)
		bufferUsed := int(numChars*2 + 2)
		if err == syscall.ERROR_INSUFFICIENT_BUFFER {
			return "", err
		}
		if err != nil {
			lastErr = err
			continue
		}

		if bufferUsed > len(buffer) {
			return "", fmt.Errorf("Windows FormatMessage reported that "+
				"message contains %d characters plus a null-terminator "+
				"(%d bytes), but the buffer can only hold %d bytes",
				numChars, bufferUsed, len(buffer))
		}
		message, _, err = sys.UTF16BytesToString(buffer[:bufferUsed])
		if err != nil {
			return "", err
		}
	}

	if message == "" {
		switch lastErr {
		case nil:
			return "", messageFiles.Err
		case ERROR_MR_MID_NOT_FOUND:
			return "", fmt.Errorf("The system cannot find message text for "+
				"message number %d in the message file for %s.", eventID, fh.File)
		default:
			return "", fh.Err
		}
	}

	return message, nil
}