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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,,