dissect.target 3.19.dev35__py3-none-any.whl → 3.19.dev37__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ from pathlib import Path
2
+
3
+ from defusedxml import ElementTree
4
+
5
+ from dissect.target import container
6
+ from dissect.target.helpers import fsutil
7
+ from dissect.target.loader import Loader
8
+ from dissect.target.target import Target
9
+
10
+
11
+ class LibvirtLoader(Loader):
12
+ """Load libvirt xml configuration files."""
13
+
14
+ def __init__(self, path: Path, **kwargs):
15
+ path = path.resolve()
16
+ self.base_dir = path.parent
17
+ super().__init__(path)
18
+
19
+ @staticmethod
20
+ def detect(path: Path) -> bool:
21
+ if path.suffix.lower() != ".xml":
22
+ return False
23
+
24
+ with path.open("rb") as fh:
25
+ lines = fh.read(512).split(b"\n")
26
+ # From what I've seen, these are are always at the start of the file
27
+ # If its generated using virt-install
28
+ needles = [b"<domain", b"<name>", b"<uuid>"]
29
+ return all(any(needle in line for line in lines) for needle in needles)
30
+
31
+ def map(self, target: Target) -> None:
32
+ xml_data = ElementTree.fromstring(self.path.read_text())
33
+ for disk in xml_data.findall("devices/disk/source"):
34
+ if not (file := disk.get("file")):
35
+ continue
36
+
37
+ for part in [fsutil.basename(file), file]:
38
+ if (path := self.base_dir.joinpath(part)).exists():
39
+ target.disks.add(container.open(path))
40
+ break
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Iterator
4
+
5
+ from dissect.target.exceptions import UnsupportedPluginError
6
+ from dissect.target.helpers.record import ChildTargetRecord
7
+ from dissect.target.plugin import ChildTargetPlugin
8
+
9
+
10
+ class QemuChildTargetPlugin(ChildTargetPlugin):
11
+ """Child target plugin that yields all QEMU domains from a KVM libvirt deamon."""
12
+
13
+ __type__ = "qemu"
14
+
15
+ def check_compatible(self) -> None:
16
+ if not self.target.fs.path("/etc/libvirt/qemu").exists():
17
+ raise UnsupportedPluginError("No libvirt QEMU installation found")
18
+
19
+ def list_children(self) -> Iterator[ChildTargetRecord]:
20
+ for domain in self.target.fs.path("/etc/libvirt/qemu").glob("*.xml"):
21
+ yield ChildTargetRecord(type=self.__type__, path=domain)
@@ -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.dev37
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
@@ -84,6 +84,7 @@ dissect/target/loaders/dir.py,sha256=F-PgvBw82XmL0rdKyBxznUkDc5Oct6-_Y9xM4fhvA6I
84
84
  dissect/target/loaders/hyperv.py,sha256=_IOUJEO0BXaCBZ6sjIX0DZTkG9UNW5Vs9VcNHYv073w,5928
85
85
  dissect/target/loaders/itunes.py,sha256=rKOhlDRypQBGkuSZudMDS1Mlb9XV6BD5FRvM7tGq9jU,13128
86
86
  dissect/target/loaders/kape.py,sha256=t5TfrGLqPeIpUUpXzIl6aHsqXMEGDqJ5YwDCs07DiBA,1237
87
+ dissect/target/loaders/libvirt.py,sha256=_3EFIytMGbiLMISHx4QXVrDebsRO6J6sMkE3TH68qsg,1374
87
88
  dissect/target/loaders/local.py,sha256=Ul-LCd_fY7SyWOVR6nH-NqbkuNpxoZVmffwrkvQElU8,16453
88
89
  dissect/target/loaders/log.py,sha256=cCkDIRS4aPlX3U-n_jUKaI2FPSV3BDpfqKceaU7rBbo,1507
89
90
  dissect/target/loaders/mqtt.py,sha256=pn2VtFh0jeYXMod4CuZOKGhe2ScQixJ1Xhx6MHe0rzk,16540
@@ -155,6 +156,7 @@ dissect/target/plugins/child/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
155
156
  dissect/target/plugins/child/docker.py,sha256=frBZ8UUzbtkT9VrK1fwUzXDAdkHESdPCb-QI_OP9Jj4,872
156
157
  dissect/target/plugins/child/esxi.py,sha256=GfgQzxntcHcyxAE2QjMJ-TrFhklweSXLbYh0uuv-klg,693
157
158
  dissect/target/plugins/child/hyperv.py,sha256=R2qVeu4p_9V53jO-65znN0LwX9v3FVA-9jbbtOQcEz8,2236
159
+ dissect/target/plugins/child/qemu.py,sha256=vNzQwzFO964jYaI67MlX8vpWyHxpegjIU5F29zHKOGI,791
158
160
  dissect/target/plugins/child/virtuozzo.py,sha256=Mx4ZxEl21g7IYkzraw4FBZup5EfrkFDv4WuTE3hxguw,1206
159
161
  dissect/target/plugins/child/vmware_workstation.py,sha256=8wkA_tSufvBUyp4XQHzRzFETf5ROlyyO_MVS3TExyfw,1570
160
162
  dissect/target/plugins/child/wsl.py,sha256=IssQgYET1T-XR5ZX2lGlNFJ_u_3QECpMF_7kXu09HTE,2469
@@ -166,7 +168,7 @@ dissect/target/plugins/filesystem/resolver.py,sha256=HfyASUFV4F9uD-yFXilFpPTORAs
166
168
  dissect/target/plugins/filesystem/walkfs.py,sha256=e8HEZcV5Wiua26FGWL3xgiQ_PIhcNvGI5KCdsAx2Nmo,2298
167
169
  dissect/target/plugins/filesystem/yara.py,sha256=zh4hU3L_egddLqDeaHDVuCWYhTlNzPYPVak36Q6IMxI,6621
168
170
  dissect/target/plugins/filesystem/ntfs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
- dissect/target/plugins/filesystem/ntfs/mft.py,sha256=2ibCLJA7yUrZshFSPKdjoNt3TpfwTtk-DaErghe91CM,11445
171
+ dissect/target/plugins/filesystem/ntfs/mft.py,sha256=WzvKSlH4egvDsuonRQ3AjYS59t9jjFX_-GOsAPLUeSk,12418
170
172
  dissect/target/plugins/filesystem/ntfs/mft_timeline.py,sha256=vvNFAZbr7s3X2OTYf4ES_L6-XsouTXcTymfxnHfZ1Rw,6791
171
173
  dissect/target/plugins/filesystem/ntfs/usnjrnl.py,sha256=uiT1ipmcAo__6VIUi8R_vvIu22vdnjMACKwLSAbzYjs,3704
172
174
  dissect/target/plugins/filesystem/ntfs/utils.py,sha256=xG7Lgw9NX4tDDrZVRm0vycFVJTOM7j-HrjqzDh0f4uA,3136
@@ -346,10 +348,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
346
348
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
347
349
  dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
348
350
  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,,
351
+ dissect.target-3.19.dev37.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
352
+ dissect.target-3.19.dev37.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
353
+ dissect.target-3.19.dev37.dist-info/METADATA,sha256=mXarkSk3Roesdmk1FGrFsYXYFROLuwmF6QxdMO3YOVQ,12719
354
+ dissect.target-3.19.dev37.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
355
+ dissect.target-3.19.dev37.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
356
+ dissect.target-3.19.dev37.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
357
+ dissect.target-3.19.dev37.dist-info/RECORD,,