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.
- dissect/target/plugins/filesystem/ntfs/mft.py +74 -52
- {dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/METADATA +1 -1
- {dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/RECORD +8 -8
- {dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/LICENSE +0 -0
- {dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/WHEEL +0 -0
- {dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/top_level.txt +0 -0
@@ -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
|
-
|
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(
|
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
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
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
|
-
|
214
|
-
|
215
|
-
|
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
|
-
|
218
|
-
|
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.
|
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=
|
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.
|
350
|
-
dissect.target-3.19.
|
351
|
-
dissect.target-3.19.
|
352
|
-
dissect.target-3.19.
|
353
|
-
dissect.target-3.19.
|
354
|
-
dissect.target-3.19.
|
355
|
-
dissect.target-3.19.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.19.dev35.dist-info → dissect.target-3.19.dev36.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|