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

Compatibility with cstruct v4 #23

Merged
merged 3 commits into from
Jun 4, 2024
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
14 changes: 6 additions & 8 deletions dissect/eventlog/bxml.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
""" Binary XML classes """

"""Binary XML classes"""

import binascii
import uuid
Expand All @@ -8,7 +7,7 @@
from io import BytesIO
from typing import Any, BinaryIO, Dict, List, Tuple

from dissect.cstruct.cstruct import cstruct
from dissect.cstruct import cstruct
from dissect.util.ts import wintimestamp

from dissect.eventlog.exceptions import BxmlException
Expand Down Expand Up @@ -146,8 +145,7 @@ def __str__(self) -> str:
WORD wMilliseconds;
};
"""
bxml_struct = cstruct()
bxml_struct.load(bxml_def)
bxml_struct = cstruct().load(bxml_def)


def read_systemtime(stream):
Expand Down Expand Up @@ -198,9 +196,9 @@ def read_sid(stream) -> str:
BxmlType.BINARY: lambda stream: binascii.hexlify(stream.read()),
BxmlType.GUID: read_guid,
BxmlType.SIZET: (
lambda stream: f"0x{bxml_struct.uint32(stream):x}"
if len(stream.getvalue()) == 4
else f"0x{bxml_struct.uint64(stream):x}"
lambda stream: (
f"0x{bxml_struct.uint32(stream):x}" if len(stream.getvalue()) == 4 else f"0x{bxml_struct.uint64(stream):x}"
)
),
BxmlType.FILETIME: lambda stream: wintimestamp(bxml_struct.uint64(stream)),
BxmlType.SYSTEMTIME: lambda stream: read_systemtime(stream),
Expand Down
9 changes: 4 additions & 5 deletions dissect/eventlog/evt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
from collections import namedtuple
from datetime import datetime, timezone

from dissect import cstruct
from dissect.cstruct import cstruct

from dissect.eventlog.exceptions import Error

c_evt = cstruct.cstruct()
c_evt.load(
"""
evt_def = """
#define ELF_LOGFILE_HEADER_DIRTY 0x0001
#define ELF_LOGFILE_HEADER_WRAP 0x0002
#define ELF_LOGFILE_LOGFULL_WRITTEN 0x0004
Expand Down Expand Up @@ -64,7 +62,8 @@
ULONG RecordSizeEnd;
} EVENTLOGEOF;
"""
)

c_evt = cstruct().load(evt_def)

EVENTLOGRECORD_SIZE = len(c_evt.EVENTLOGRECORD)

Expand Down
17 changes: 8 additions & 9 deletions dissect/eventlog/evtx.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
import logging
import os

from dissect import cstruct
from dissect.cstruct import cstruct

from dissect.eventlog.bxml import Bxml, BxmlSub, EvtxNameReader, parse_bxml
from dissect.eventlog.exceptions import MalformedElfChnkException

log = logging.getLogger(__name__)
log.setLevel(os.getenv("DISSECT_LOG_EVTX", "CRITICAL"))

evtx = cstruct.cstruct()
evtx.load(
"""
evtx_def = """
struct EVTX_HEADER {
char magic[8];
uint64 first_chunk;
Expand Down Expand Up @@ -57,14 +55,15 @@
uint32 size_copy;
};
"""
)

c_evtx = cstruct().load(evtx_def)


class ElfChnk:
def __init__(self, d, path=None):
self.path = path
self.stream = io.BytesIO(d)
self.header = evtx.EVTX_CHUNK(self.stream)
self.header = c_evtx.EVTX_CHUNK(self.stream)

if self.header.magic != b"ElfChnk\x00":
if self.header.magic != b"\x00\x00\x00\x00\x00\x00\x00\x00":
Expand All @@ -83,7 +82,7 @@ def read(self, records=True):
while True:
offset = self.stream.tell()
try:
r = evtx.EVTX_RECORD(self.stream)
r = c_evtx.EVTX_RECORD(self.stream)
except EOFError:
break

Expand Down Expand Up @@ -129,13 +128,13 @@ class Evtx:
def __init__(self, fh, path=None):
self.path = path
self.fh = fh
self.header = evtx.EVTX_HEADER(self.fh)
self.header = c_evtx.EVTX_HEADER(self.fh)
self.count = 0

def __iter__(self):
chunk_offset = self.header.header_block_size

skip = self.header.header_block_size - len(evtx.EVTX_HEADER)
skip = self.header.header_block_size - len(c_evtx.EVTX_HEADER)
if skip > 0:
self.fh.read(skip)

Expand Down
7 changes: 3 additions & 4 deletions dissect/eventlog/wevt.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import dissect.eventlog.wevt_object as wevt_objects
from dissect.eventlog.exceptions import UnknownSignatureException

header_dev = """
header_def = """
struct Event_Descriptor {
char ProviderId[16];
uint32 offset;
Expand Down Expand Up @@ -40,8 +40,7 @@
};
"""

c_wevt_headers = cstruct()
c_wevt_headers.load(header_dev)
c_wevt_headers = cstruct().load(header_def)


def validate_signature(signature, expected_signature):
Expand Down Expand Up @@ -120,7 +119,7 @@
return self.header.size

def __repr__(self):
return f"<WEVT providerid={self.provider_id} payload_size={self.payload_size} header={self.header}>"
return f"<WEVT provider_id={self.provider_id} payload_size={self.payload_size} header={self.header}>"

Check warning on line 122 in dissect/eventlog/wevt.py

View check run for this annotation

Codecov / codecov/patch

dissect/eventlog/wevt.py#L122

Added line #L122 was not covered by tests


class WEVT_TYPE:
Expand Down
59 changes: 29 additions & 30 deletions dissect/eventlog/wevt_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,47 @@
};

struct TEMP {
char signature[4];
uint32 size;
uint32 nr_of_items;
uint32 nr_of_names;
uint32 data_offset;
uint32 binxml_fragments;
char identifier[16];
char signature[4];
uint32 size;
uint32 nr_of_items;
uint32 nr_of_names;
uint32 data_offset;
uint32 binxml_fragments;
char identifier[16];
};

struct TEMP_DESCRIPTOR {
uint32 unknown0;
uint8 input_type;
uint8 output_type;
uint16 unknown1;
uint32 unknown2;
uint32 unknown3;
uint32 data_offset;
uint32 unknown0;
uint8 input_type;
uint8 output_type;
uint16 unknown1;
uint32 unknown2;
uint32 unknown3;
uint32 data_offset;
}

struct PRVA {
uint32 unknown;
uint32 data_offset;
uint32 unknown;
uint32 data_offset;
};

struct TASK {
uint32 id;
uint32 message_table_id;
char mui_id[16];
uint32 data_offset;
uint32 id;
uint32 message_table_id;
char mui_id[16];
uint32 data_offset;
};

struct KEYW {
uint64 bitmask;
uint32 message_table_id;
uint32 data_offset;
uint64 bitmask;
uint32 message_table_id;
uint32 data_offset;
};

struct LEVL {
uint32 id;
uint32 message_table_id;
uint32 data_offset;
uint32 id;
uint32 message_table_id;
uint32 data_offset;
};

struct EVNT {
Expand Down Expand Up @@ -101,24 +101,23 @@
};
"""

wevt_objects = cstruct()
wevt_objects.load(wevt_object_def)
c_wevt_objects = cstruct().load(wevt_object_def)


class WevtObject:
"""Base object that functions as a wrapper for the header"""

def __init__(self, offset, data):
self.offset = offset
self.header = getattr(wevt_objects, self.__class__.__name__)(data)
self.header = getattr(c_wevt_objects, self.__class__.__name__)(data)
self.data = data[len(self.header) :]
self.data_start = self.offset + len(self.header)
self.data_offset = self.header.data_offset - self.data_start

def extract_name(self, data_offset):
"""data_offset is a relative offset that usually points to the data_item.
This point is used to read the name for this specific"""
return wevt_objects.DATA_ITEM(self.data[data_offset:]).name.rstrip("\x00")
return c_wevt_objects.DATA_ITEM(self.data[data_offset:]).name.rstrip("\x00")

def __getattribute__(self, name: str):
try:
Expand Down
10 changes: 8 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ classifiers = [
"Topic :: Utilities",
]
dependencies = [
"dissect.cstruct>=3.0.dev,<4.0.dev",
"dissect.util>=3.0.dev,<4.0.dev",
"dissect.cstruct>=4.dev,<5",
"dissect.util>=3,<4",
]
dynamic = ["version"]

Expand All @@ -35,6 +35,12 @@ homepage = "https://dissect.tools"
documentation = "https://docs.dissect.tools/en/latest/projects/dissect.eventlog"
repository = "https://github.com/fox-it/dissect.eventlog"

[project.optional-dependencies]
dev = [
"dissect.cstruct>=4.0.dev,<5.0.dev",
"dissect.util>=3.0.dev,<4.0.dev",
]

[tool.black]
line-length = 120

Expand Down
5 changes: 2 additions & 3 deletions tests/_utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from dissect.cstruct import cstruct

from dissect.eventlog.wevt import header_dev
from dissect.eventlog.wevt import header_def
from dissect.eventlog.wevt_object import wevt_object_def

definitions = cstruct()
definitions.load(header_dev + wevt_object_def)
definitions = cstruct().load(header_def + wevt_object_def)


def create_header(type, **kwargs):
Expand Down
5 changes: 3 additions & 2 deletions tests/test_wevt.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ def test_wevt_test_offset(value, expected_result, mocked_fh):
def test_wevt_test_iterator(_, mocked_fh):
with patch.object(WEVT, WEVT._next_type_offset.__name__):
wevt = create_wevt(mocked_fh)
for index, _ in enumerate(wevt):
wevt._next_type_offset.assert_called_with(wevt.payload_types[index].offset)
with patch("dissect.cstruct.types.char.Char._read_array"):
for index, _ in enumerate(wevt):
wevt._next_type_offset.assert_called_with(wevt.payload_types[index].offset)


@pytest.mark.parametrize(
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ minversion = 4.4.3
requires = virtualenv>=20.16.6

[testenv]
extras = dev
deps =
pytest
pytest-cov
Expand Down