dissect.target 3.16.dev31__py3-none-any.whl → 3.16.dev33__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,7 +60,10 @@ class TarFilesystem(Filesystem):
60
60
  @staticmethod
61
61
  def _detect(fh: BinaryIO) -> bool:
62
62
  """Detect a tar file on a given file-like object."""
63
- return tarfile.is_tarfile(fh)
63
+ fh = fsutil.open_decompress(fileobj=fh)
64
+
65
+ fh.seek(257)
66
+ return fh.read(8) in (tarfile.GNU_MAGIC, tarfile.POSIX_MAGIC)
64
67
 
65
68
  def get(self, path: str, relentry: Optional[FilesystemEntry] = None) -> FilesystemEntry:
66
69
  """Returns a TarFilesystemEntry object corresponding to the given path."""
@@ -14,69 +14,6 @@ from dissect.target.target import Target
14
14
  camel_case_patterns = [re.compile(r"(\S)([A-Z][a-z]+)"), re.compile(r"([a-z0-9])([A-Z])"), re.compile(r"(\w)[.\s](\w)")]
15
15
 
16
16
 
17
- def _collect_wer_data(wer_file: Path) -> tuple[list[tuple[str, str]], dict[str, str]]:
18
- """Parse data from a .wer file."""
19
- record_values = {}
20
- record_fields = []
21
- key = None
22
-
23
- # Default encoding when no BOM is present
24
- encoding = "utf-16-le"
25
-
26
- # If a BOM header is present we can decode it using utf-16
27
- with wer_file.open("rb") as fh:
28
- if fh.read(len(codecs.BOM)) in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE):
29
- encoding = "utf-16"
30
-
31
- for line in wer_file.read_text(encoding).splitlines():
32
- if len(line_split := line.rstrip().split("=", 1)) == 2:
33
- name, value = line_split
34
- record_type = "string"
35
-
36
- # dynamic entry with key and value on separate lines
37
- if "].Name" in name and not key:
38
- key = value
39
- # set key and continue to get value on the next line
40
- continue
41
-
42
- # dynamic entry with key and value on the same line
43
- elif "]." in name and not key:
44
- category, name = name.split(".", 1)
45
- key = f"{category.split('[')[0]}{name}"
46
-
47
- if "EventTime" in name:
48
- value = wintimestamp(int(value))
49
- record_type = "datetime"
50
- key = "ts"
51
-
52
- key = _key_to_snake_case(key if key else name)
53
-
54
- record_values[key] = value
55
- record_fields.append((record_type, key)) if key != "ts" else record_fields.insert(0, (record_type, key))
56
- # reset key necessary for dynamic entries and ts
57
- key = None
58
-
59
- return record_fields, record_values
60
-
61
-
62
- def _collect_wer_metadata(metadata_xml_file: Path) -> tuple[list[tuple[str, str]], dict[str, str]]:
63
- """Parse data from a metadata .xml file linked to a .wer file."""
64
- record_fields = []
65
- record_values = {}
66
- file = metadata_xml_file.read_text("utf-16")
67
-
68
- tree = ElementTree.fromstring(file)
69
- for metadata in tree.iter("WERReportMetadata"):
70
- for category in metadata:
71
- for value in category:
72
- if record_value := value.text.strip("\t\n"):
73
- key = _key_to_snake_case(f"{category.tag}{value.tag}")
74
- record_fields.append(("string", key))
75
- record_values[key] = record_value
76
-
77
- return record_fields, record_values
78
-
79
-
80
17
  def _create_record_descriptor(record_name: str, record_fields: list[tuple[str, str]]) -> TargetRecordDescriptor:
81
18
  record_fields.extend(
82
19
  [
@@ -87,12 +24,6 @@ def _create_record_descriptor(record_name: str, record_fields: list[tuple[str, s
87
24
  return TargetRecordDescriptor(record_name, record_fields)
88
25
 
89
26
 
90
- def _key_to_snake_case(key: str) -> str:
91
- for pattern in camel_case_patterns:
92
- key = pattern.sub(r"\1_\2", key)
93
- return key.lower()
94
-
95
-
96
27
  class WindowsErrorReportingPlugin(Plugin):
97
28
  """Plugin for parsing Windows Error Reporting files."""
98
29
 
@@ -116,6 +47,98 @@ class WindowsErrorReportingPlugin(Plugin):
116
47
  if not self.wer_files:
117
48
  raise UnsupportedPluginError("No Windows Error Reporting directories found.")
118
49
 
50
+ def _sanitize_key(self, key: str) -> str:
51
+ # Convert camel case to snake case
52
+ for pattern in camel_case_patterns:
53
+ key = pattern.sub(r"\1_\2", key)
54
+
55
+ # Keep only basic characters in key
56
+ key = re.sub(r"[^a-zA-Z0-9_]", "", key)
57
+
58
+ return key.lower()
59
+
60
+ def _collect_wer_data(self, wer_file: Path) -> tuple[list[tuple[str, str]], dict[str, str]]:
61
+ """Parse data from a .wer file."""
62
+ record_values = {}
63
+ record_fields = []
64
+ key = None
65
+
66
+ # Default encoding when no BOM is present
67
+ encoding = "utf-16-le"
68
+
69
+ # If a BOM header is present we can decode it using utf-16
70
+ with wer_file.open("rb") as fh:
71
+ if fh.read(len(codecs.BOM)) in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE):
72
+ encoding = "utf-16"
73
+
74
+ for line in wer_file.read_text(encoding).splitlines():
75
+ if len(line_split := line.rstrip().split("=", 1)) != 2:
76
+ continue
77
+
78
+ name, value = line_split
79
+ record_type = "string"
80
+
81
+ # Dynamic entry with key and value on separate lines
82
+ if "].Name" in name and not key:
83
+ key = value
84
+ # Set key and continue to get value on the next line
85
+ continue
86
+
87
+ # Dynamic entry with key and value on the same line
88
+ elif "]." in name and not key:
89
+ category, name = name.split(".", 1)
90
+ key = f"{category.split('[')[0]}{name}"
91
+
92
+ if "EventTime" in name:
93
+ value = wintimestamp(int(value))
94
+ record_type = "datetime"
95
+ key = "ts"
96
+
97
+ key = self._sanitize_key(key if key else name)
98
+ if not key:
99
+ self.target.log.warning(f"Sanitizing key resulted in empty key, skipping line '{line}'.")
100
+ key = None
101
+ continue
102
+
103
+ if key in record_values:
104
+ self.target.log.warning(f"Key does already exist, skipping line '{line}'.")
105
+ key = None
106
+ continue
107
+
108
+ record_values[key] = value
109
+ record_fields.append((record_type, key)) if key != "ts" else record_fields.insert(0, (record_type, key))
110
+ # Reset key necessary for dynamic entries and ts
111
+ key = None
112
+
113
+ return record_fields, record_values
114
+
115
+ def _collect_wer_metadata(self, metadata_xml_file: Path) -> tuple[list[tuple[str, str]], dict[str, str]]:
116
+ """Parse data from a metadata .xml file linked to a .wer file."""
117
+ record_fields = []
118
+ record_values = {}
119
+ file = metadata_xml_file.read_text("utf-16")
120
+
121
+ tree = ElementTree.fromstring(file)
122
+ for metadata in tree.iter("WERReportMetadata"):
123
+ for category in metadata:
124
+ for value in category:
125
+ if not (record_value := value.text.strip("\t\n")):
126
+ continue
127
+
128
+ key = self._sanitize_key(f"{category.tag}{value.tag}")
129
+ if not key:
130
+ self.target.log.warning(f"Sanitizing key resulted in empty key, skipping value '{value}'.")
131
+ continue
132
+
133
+ if key in record_values:
134
+ self.target.log.warning(f"Key already exists, skipping value '{value}'.")
135
+ continue
136
+
137
+ record_fields.append(("string", key))
138
+ record_values[key] = record_value
139
+
140
+ return record_fields, record_values
141
+
119
142
  @export(record=DynamicDescriptor(["path", "string", "datetime"]))
120
143
  def wer(self) -> Iterator[DynamicDescriptor]:
121
144
  """Return information from Windows Error Reporting (WER) files.
@@ -158,13 +181,13 @@ class WindowsErrorReportingPlugin(Plugin):
158
181
  for file in files:
159
182
  if file.suffix == ".wer":
160
183
  record_values["wer_file_path"] = file
161
- wer_report_fields, wer_report_values = _collect_wer_data(file)
184
+ wer_report_fields, wer_report_values = self._collect_wer_data(file)
162
185
  # make sure wer_report_fields are the first entries in the list
163
186
  record_fields = wer_report_fields + record_fields
164
187
  record_values = record_values | wer_report_values
165
188
  elif ".WERInternalMetadata" in file.suffixes:
166
189
  record_values["metadata_file_path"] = file
167
- metadata_fields, metadata_values = _collect_wer_metadata(file)
190
+ metadata_fields, metadata_values = self._collect_wer_metadata(file)
168
191
  record_fields.extend(metadata_fields)
169
192
  record_values = metadata_values | record_values
170
193
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.16.dev31
3
+ Version: 3.16.dev33
4
4
  Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -36,7 +36,7 @@ dissect/target/filesystems/jffs.py,sha256=Ceqa5Em2pepnXMH_XZFmSNjQyWPo1uWTthBFSM
36
36
  dissect/target/filesystems/ntfs.py,sha256=fGgCKjdO5GrPC21DDr0SwIxmwR7KruNIqGUzysboirA,7068
37
37
  dissect/target/filesystems/smb.py,sha256=uxfcOWwEoDCw8Qpsa94T5Pn-SKd4WXs4OOrzVVI55d8,6406
38
38
  dissect/target/filesystems/squashfs.py,sha256=ehzlThXB7n96XUvQnsK5tWLsA9HIxYN-Zxl7aO9D7ts,3921
39
- dissect/target/filesystems/tar.py,sha256=Tg9XqLJajqxt11wlnDAdkf-ufiJwlGvtkV1oKqeuf8k,5590
39
+ dissect/target/filesystems/tar.py,sha256=kQNhcEDPX005svse039OeR2AGSDigGuGz2AKoVrgg84,5692
40
40
  dissect/target/filesystems/vmfs.py,sha256=sRtYBUAKTKcHrjCXqpFJ8GIVU-ERjqxhB2zXBndtcXU,4955
41
41
  dissect/target/filesystems/xfs.py,sha256=kIyFGKYlyFYC7H3jaEv-lNKtBW4ZkD92H0WpfGcr1ww,4498
42
42
  dissect/target/filesystems/zip.py,sha256=WT1bQhzX_1MXXVZTKrJniae4xqRqMZ8FsfbvhgGQRTQ,4462
@@ -270,7 +270,7 @@ dissect/target/plugins/os/windows/syscache.py,sha256=WBDx6rixaVnCRsJHLLN_9YWoTDb
270
270
  dissect/target/plugins/os/windows/tasks.py,sha256=8DRsIAuIJPaH_G18l8RYfnK_WkEqVx2xDJ1FnIc_i0g,5716
271
271
  dissect/target/plugins/os/windows/thumbcache.py,sha256=23YjOjTNoE7BYITmg8s9Zs8Wih2e73BkJJEaKlfotcI,4133
272
272
  dissect/target/plugins/os/windows/ual.py,sha256=TYF-R46klEa_HHb86UJd6mPrXwHlAMOUTzC0pZ8uiq0,9787
273
- dissect/target/plugins/os/windows/wer.py,sha256=OId9gnqU-z2D_Xl51J9THWTIegre06QsftWnGz7IQb4,7563
273
+ dissect/target/plugins/os/windows/wer.py,sha256=1kwkBvgmEU1QRCLWVmUFNIWAqXEEGtAj2c8uj0iusOE,8625
274
274
  dissect/target/plugins/os/windows/dpapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
275
275
  dissect/target/plugins/os/windows/dpapi/blob.py,sha256=oFhksgx2BAaeAbpPwOM-o0Dw5MKaMLGMF6ETdxIS708,5051
276
276
  dissect/target/plugins/os/windows/dpapi/crypto.py,sha256=Xd15dFLYOQtvk9SlkdM1XX0c2vxSj9j4RFEwV70eP5Y,9074
@@ -331,10 +331,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
331
331
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
332
332
  dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
333
333
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
334
- dissect.target-3.16.dev31.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
335
- dissect.target-3.16.dev31.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
336
- dissect.target-3.16.dev31.dist-info/METADATA,sha256=bQJydAA40PRNfKgAuW4LJCissMW3rELgyfBIyapzadU,11107
337
- dissect.target-3.16.dev31.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
338
- dissect.target-3.16.dev31.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
339
- dissect.target-3.16.dev31.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
340
- dissect.target-3.16.dev31.dist-info/RECORD,,
334
+ dissect.target-3.16.dev33.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
335
+ dissect.target-3.16.dev33.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
336
+ dissect.target-3.16.dev33.dist-info/METADATA,sha256=CslSUR0Z9B6LGdHxl0SzzwC405b76fEMiaTuFa24Myk,11107
337
+ dissect.target-3.16.dev33.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
338
+ dissect.target-3.16.dev33.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
339
+ dissect.target-3.16.dev33.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
340
+ dissect.target-3.16.dev33.dist-info/RECORD,,