dissect.target 3.19.dev35__py3-none-any.whl → 3.19.dev36__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.
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  from typing import Callable, Iterator
3
5
 
@@ -8,6 +10,7 @@ from flow.record import Record
8
10
  from flow.record.fieldtypes import windows_path
9
11
 
10
12
  from dissect.target.exceptions import UnsupportedPluginError
13
+ from dissect.target.filesystems.ntfs import NtfsFilesystem
11
14
  from dissect.target.helpers.record import TargetRecordDescriptor
12
15
  from dissect.target.plugin import Plugin, arg, export
13
16
  from dissect.target.plugins.filesystem.ntfs.utils import (
@@ -119,9 +122,12 @@ COMPACT_RECORD_TYPES = {
119
122
 
120
123
 
121
124
  class MftPlugin(Plugin):
125
+ def __init__(self, target):
126
+ super().__init__(target)
127
+ self.ntfs_filesystems = {index: fs for index, fs in enumerate(self.target.filesystems) if fs.__type__ == "ntfs"}
128
+
122
129
  def check_compatible(self) -> None:
123
- ntfs_filesystems = [fs for fs in self.target.filesystems if fs.__type__ == "ntfs"]
124
- if not len(ntfs_filesystems):
130
+ if not len(self.ntfs_filesystems):
125
131
  raise UnsupportedPluginError("No NTFS filesystems found")
126
132
 
127
133
  @export(
@@ -133,12 +139,17 @@ class MftPlugin(Plugin):
133
139
  ]
134
140
  )
135
141
  @arg("--compact", action="store_true", help="compacts the MFT entry timestamps into a single record")
142
+ @arg("--fs", type=int, default=None, help="optional filesystem index, zero indexed")
143
+ @arg("--start", type=int, default=0, help="the first MFT segment number")
144
+ @arg("--end", type=int, default=-1, help="the last MFT segment number")
136
145
  @arg(
137
146
  "--macb",
138
147
  action="store_true",
139
148
  help="compacts the MFT entry timestamps into aggregated records with MACB bitfield",
140
149
  )
141
- def mft(self, compact: bool = False, macb: bool = False):
150
+ def mft(
151
+ self, compact: bool = False, fs: int | None = None, start: int = 0, end: int = -1, macb: bool = False
152
+ ) -> Iterator[Record]:
142
153
  """Return the MFT records of all NTFS filesystems.
143
154
 
144
155
  The Master File Table (MFT) contains primarily metadata about every file and folder on a NFTS filesystem.
@@ -167,55 +178,66 @@ class MftPlugin(Plugin):
167
178
  elif macb:
168
179
  aggr = macb_aggr
169
180
 
170
- for fs in self.target.filesystems:
171
- if fs.__type__ != "ntfs":
172
- continue
173
-
174
- # If this filesystem is a "fake" NTFS filesystem, used to enhance a
175
- # VirtualFilesystem, The driveletter (more accurate mount point)
176
- # returned will be that of the VirtualFilesystem. This makes sure
177
- # the paths returned in the records are actually reachable.
178
- drive_letter = get_drive_letter(self.target, fs)
179
- volume_uuid = get_volume_identifier(fs)
180
-
181
+ if fs is not None:
181
182
  try:
182
- for record in fs.ntfs.mft.segments():
183
- try:
184
- inuse = bool(record.header.Flags & FILE_RECORD_SEGMENT_IN_USE)
185
- owner, _ = get_owner_and_group(record, fs)
186
- resident = False
187
- size = None
188
-
189
- if not record.is_dir():
190
- for data_attribute in record.attributes.DATA:
191
- if data_attribute.name == "":
192
- resident = data_attribute.resident
193
- break
194
-
195
- size = get_record_size(record)
196
-
197
- for path in record.full_paths():
198
- path = f"{drive_letter}{path}"
199
- yield from aggr(
200
- self.mft_records(
201
- drive_letter=drive_letter,
202
- record=record,
203
- segment=record.segment,
204
- path=path,
205
- owner=owner,
206
- size=size,
207
- resident=resident,
208
- inuse=inuse,
209
- volume_uuid=volume_uuid,
210
- record_formatter=record_formatter,
211
- )
183
+ filesystem = self.ntfs_filesystems[fs]
184
+ except KeyError:
185
+ self.target.log.error("NTFS filesystem with index number %s does not exist", fs)
186
+ return
187
+
188
+ yield from self.segments(filesystem, record_formatter, aggr, start, end)
189
+ else:
190
+ for filesystem in self.ntfs_filesystems.values():
191
+ yield from self.segments(filesystem, record_formatter, aggr, start, end)
192
+
193
+ def segments(
194
+ self, fs: NtfsFilesystem, record_formatter: Callable, aggr: Callable, start: int, end: int
195
+ ) -> Iterator[Record]:
196
+ # If this filesystem is a "fake" NTFS filesystem, used to enhance a
197
+ # VirtualFilesystem, The driveletter (more accurate mount point)
198
+ # returned will be that of the VirtualFilesystem. This makes sure
199
+ # the paths returned in the records are actually reachable.
200
+ drive_letter = get_drive_letter(self.target, fs)
201
+ volume_uuid = get_volume_identifier(fs)
202
+
203
+ try:
204
+ for record in fs.ntfs.mft.segments(start, end):
205
+ try:
206
+ inuse = bool(record.header.Flags & FILE_RECORD_SEGMENT_IN_USE)
207
+ owner, _ = get_owner_and_group(record, fs)
208
+ resident = None
209
+ size = None
210
+
211
+ if not record.is_dir():
212
+ for data_attribute in record.attributes.DATA:
213
+ if data_attribute.name == "":
214
+ resident = data_attribute.resident
215
+ break
216
+
217
+ size = get_record_size(record)
218
+
219
+ for path in record.full_paths():
220
+ path = f"{drive_letter}{path}"
221
+ yield from aggr(
222
+ self.mft_records(
223
+ drive_letter=drive_letter,
224
+ record=record,
225
+ segment=record.segment,
226
+ path=path,
227
+ owner=owner,
228
+ size=size,
229
+ resident=resident,
230
+ inuse=inuse,
231
+ volume_uuid=volume_uuid,
232
+ record_formatter=record_formatter,
212
233
  )
213
- except Exception as e:
214
- self.target.log.warning("An error occured parsing MFT segment %d: %s", record.segment, str(e))
215
- self.target.log.debug("", exc_info=e)
234
+ )
235
+ except Exception as e:
236
+ self.target.log.warning("An error occured parsing MFT segment %d: %s", record.segment, str(e))
237
+ self.target.log.debug("", exc_info=e)
216
238
 
217
- except Exception:
218
- log.exception("An error occured constructing FilesystemRecords")
239
+ except Exception:
240
+ log.exception("An error occured constructing FilesystemRecords")
219
241
 
220
242
  def mft_records(
221
243
  self,
@@ -229,7 +251,7 @@ class MftPlugin(Plugin):
229
251
  inuse: bool,
230
252
  volume_uuid: str,
231
253
  record_formatter: Callable,
232
- ):
254
+ ) -> Iterator[Record]:
233
255
  for attr in record.attributes.STANDARD_INFORMATION:
234
256
  yield from record_formatter(
235
257
  attr=attr,
@@ -286,7 +308,7 @@ class MftPlugin(Plugin):
286
308
  )
287
309
 
288
310
 
289
- def compacted_formatter(attr: Attribute, record_type: InformationType, **kwargs):
311
+ def compacted_formatter(attr: Attribute, record_type: InformationType, **kwargs) -> Iterator[Record]:
290
312
  record_desc = COMPACT_RECORD_TYPES.get(record_type)
291
313
  yield record_desc(
292
314
  creation_time=attr.creation_time,
@@ -297,7 +319,7 @@ def compacted_formatter(attr: Attribute, record_type: InformationType, **kwargs)
297
319
  )
298
320
 
299
321
 
300
- def formatter(attr: Attribute, record_type: InformationType, **kwargs):
322
+ def formatter(attr: Attribute, record_type: InformationType, **kwargs) -> Iterator[Record]:
301
323
  record_desc = RECORD_TYPES.get(record_type)
302
324
  for type, timestamp in [
303
325
  ("B", attr.creation_time),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.19.dev35
3
+ Version: 3.19.dev36
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
@@ -166,7 +166,7 @@ dissect/target/plugins/filesystem/resolver.py,sha256=HfyASUFV4F9uD-yFXilFpPTORAs
166
166
  dissect/target/plugins/filesystem/walkfs.py,sha256=e8HEZcV5Wiua26FGWL3xgiQ_PIhcNvGI5KCdsAx2Nmo,2298
167
167
  dissect/target/plugins/filesystem/yara.py,sha256=zh4hU3L_egddLqDeaHDVuCWYhTlNzPYPVak36Q6IMxI,6621
168
168
  dissect/target/plugins/filesystem/ntfs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
- dissect/target/plugins/filesystem/ntfs/mft.py,sha256=2ibCLJA7yUrZshFSPKdjoNt3TpfwTtk-DaErghe91CM,11445
169
+ dissect/target/plugins/filesystem/ntfs/mft.py,sha256=WzvKSlH4egvDsuonRQ3AjYS59t9jjFX_-GOsAPLUeSk,12418
170
170
  dissect/target/plugins/filesystem/ntfs/mft_timeline.py,sha256=vvNFAZbr7s3X2OTYf4ES_L6-XsouTXcTymfxnHfZ1Rw,6791
171
171
  dissect/target/plugins/filesystem/ntfs/usnjrnl.py,sha256=uiT1ipmcAo__6VIUi8R_vvIu22vdnjMACKwLSAbzYjs,3704
172
172
  dissect/target/plugins/filesystem/ntfs/utils.py,sha256=xG7Lgw9NX4tDDrZVRm0vycFVJTOM7j-HrjqzDh0f4uA,3136
@@ -346,10 +346,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
346
346
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
347
347
  dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
348
348
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
349
- dissect.target-3.19.dev35.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
350
- dissect.target-3.19.dev35.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
351
- dissect.target-3.19.dev35.dist-info/METADATA,sha256=3ApP47TWFjPe5wV6_fuejtFbpr7YL-bwmvPePNKfN1M,12719
352
- dissect.target-3.19.dev35.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
353
- dissect.target-3.19.dev35.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
354
- dissect.target-3.19.dev35.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
355
- dissect.target-3.19.dev35.dist-info/RECORD,,
349
+ dissect.target-3.19.dev36.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
350
+ dissect.target-3.19.dev36.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
351
+ dissect.target-3.19.dev36.dist-info/METADATA,sha256=MWrzVxs5DUZf35Z7ZkNFIJ7s3CIJdFUM-b5aQiko0HU,12719
352
+ dissect.target-3.19.dev36.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
353
+ dissect.target-3.19.dev36.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
354
+ dissect.target-3.19.dev36.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
355
+ dissect.target-3.19.dev36.dist-info/RECORD,,