mirror of
https://github.com/Velocidex/velociraptor.git
synced 2026-10-12 02:09:59 +00:00
Problem: When Windows event logs are cleared or deleted, Windows.EventLogs.Cleared can show that a log was cleared, but the events themselves are lost because parse_evtx() only reads intact log files. The old data usually stays on disk, in unallocated space, the pagefile or memory, until it is overwritten. Solution: This PR adds a new carve_evtx() VQL plugin. It scans any file or device for EVTX chunk signatures at any offset and parses each 64KB chunk on its own. - Rows have the same structure as parse_evtx(), plus ChunkOffset, ChunkHeaderValid, ChunkDataValid, ChunkTruncated and ChunkCompressed. - NTFS-compressed chunks (the Windows default for event logs) are decompressed. - Damaged chunks are flagged, not dropped. - With output=, the recovered events are also written to a new .evtx file that Event Viewer can open. Example: SELECT * FROM carve_evtx(filename='''\\.\C:''', accessor="raw_file") WHERE System.Channel = "Application" Known limitation Old records in chunk slack are not recovered yet. This could be a follow-up. --------- Co-authored-by: Mike Cohen <[email protected]>
50 lines
1.2 KiB
Go
50 lines
1.2 KiB
Go
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// Reading past the end with Read() sets a sticky EOF flag. ReadAt()
|
|
// must not be affected by it.
|
|
func TestReadSeekReaderAdapterReadAt(t *testing.T) {
|
|
data := []byte("0123456789")
|
|
adapter := NewReadSeekReaderAdapter(bytes.NewReader(data), nil)
|
|
adapter.SetSize(int64(len(data)))
|
|
|
|
// Exhaust the reader with Read().
|
|
_, err := io.ReadAll(adapter)
|
|
assert.NoError(t, err)
|
|
|
|
n, err := adapter.Read(make([]byte, 1))
|
|
assert.Equal(t, 0, n)
|
|
assert.Equal(t, io.EOF, err)
|
|
|
|
// ReadAt still works anywhere in the file.
|
|
buf := make([]byte, 4)
|
|
n, err = adapter.ReadAt(buf, 2)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "2345", string(buf[:n]))
|
|
|
|
// A read crossing the size is cut short with EOF.
|
|
n, err = adapter.ReadAt(buf, 8)
|
|
assert.Equal(t, io.EOF, err)
|
|
assert.Equal(t, "89", string(buf[:n]))
|
|
|
|
// Reading past the end does not break later reads.
|
|
n, err = adapter.ReadAt(buf, 20)
|
|
assert.Equal(t, 0, n)
|
|
assert.Equal(t, io.EOF, err)
|
|
|
|
n, err = adapter.ReadAt(buf, 0)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "0123", string(buf[:n]))
|
|
|
|
// MakeReaderAtter uses the stateless ReadAt.
|
|
_, ok := MakeReaderAtter(adapter).(*ReadSeekReaderAdapter)
|
|
assert.True(t, ok)
|
|
}
|