dissect.target 3.16.dev39__py3-none-any.whl → 3.16.dev43__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,23 +16,23 @@ from typing import Any, BinaryIO, Iterator, Optional, Sequence, TextIO, Union
16
16
  try:
17
17
  import lzma
18
18
 
19
- HAVE_XZ = True
19
+ HAS_XZ = True
20
20
  except ImportError:
21
- HAVE_XZ = False
21
+ HAS_XZ = False
22
22
 
23
23
  try:
24
24
  import bz2
25
25
 
26
- HAVE_BZ2 = True
26
+ HAS_BZ2 = True
27
27
  except ImportError:
28
- HAVE_BZ2 = False
28
+ HAS_BZ2 = False
29
29
 
30
30
  try:
31
31
  import zstandard
32
32
 
33
- HAVE_ZSTD = True
33
+ HAS_ZSTD = True
34
34
  except ImportError:
35
- HAVE_ZSTD = False
35
+ HAS_ZSTD = False
36
36
 
37
37
  import dissect.target.filesystem as filesystem
38
38
  from dissect.target.exceptions import FileNotFoundError, SymlinkRecursionError
@@ -511,14 +511,14 @@ def open_decompress(
511
511
  if magic[:2] == b"\x1f\x8b":
512
512
  return gzip.open(file, mode, encoding=encoding, errors=errors, newline=newline)
513
513
 
514
- if HAVE_XZ and magic[:5] == b"\xfd7zXZ":
514
+ if HAS_XZ and magic[:5] == b"\xfd7zXZ":
515
515
  return lzma.open(file, mode, encoding=encoding, errors=errors, newline=newline)
516
516
 
517
- if HAVE_BZ2 and magic[:3] == b"BZh" and 0x31 <= magic[3] <= 0x39:
517
+ if HAS_BZ2 and magic[:3] == b"BZh" and 0x31 <= magic[3] <= 0x39:
518
518
  # In a valid bz2 header the 4th byte is in the range b'1' ... b'9'.
519
519
  return bz2.open(file, mode, encoding=encoding, errors=errors, newline=newline)
520
520
 
521
- if HAVE_ZSTD and magic[:4] in [b"\xfd\x2f\xb5\x28", b"\x28\xb5\x2f\xfd"]:
521
+ if HAS_ZSTD and magic[:4] in [b"\xfd\x2f\xb5\x28", b"\x28\xb5\x2f\xfd"]:
522
522
  # stream_reader is not seekable, so we have to resort to the less
523
523
  # efficient decompressor which returns bytes.
524
524
  return io.BytesIO(zstandard.decompress(file.read()))
@@ -34,12 +34,12 @@ def find_entry_path(path: Path) -> str | None:
34
34
  return prefix
35
35
 
36
36
 
37
- def map_dirs(target: Target, dirs: list[Path], os_type: str, **kwargs) -> None:
37
+ def map_dirs(target: Target, dirs: list[Path | tuple[str, Path]], os_type: str, **kwargs) -> None:
38
38
  """Map directories as filesystems into the given target.
39
39
 
40
40
  Args:
41
41
  target: The target to map into.
42
- dirs: The directories to map as filesystems.
42
+ dirs: The directories to map as filesystems. If a list member is a tuple, the first element is the drive letter.
43
43
  os_type: The operating system type, used to determine how the filesystem should be mounted.
44
44
  """
45
45
  alt_separator = ""
@@ -49,6 +49,12 @@ def map_dirs(target: Target, dirs: list[Path], os_type: str, **kwargs) -> None:
49
49
  case_sensitive = False
50
50
 
51
51
  for path in dirs:
52
+ drive_letter = None
53
+ if isinstance(path, tuple):
54
+ drive_letter, path = path
55
+ elif is_drive_letter_path(path):
56
+ drive_letter = path.name[0]
57
+
52
58
  if isinstance(path, zipfile.Path):
53
59
  dfs = ZipFilesystem(path.root.fp, path.at, alt_separator=alt_separator, case_sensitive=case_sensitive)
54
60
  else:
@@ -58,8 +64,8 @@ def map_dirs(target: Target, dirs: list[Path], os_type: str, **kwargs) -> None:
58
64
  if os_type == OperatingSystem.WINDOWS:
59
65
  loaderutil.add_virtual_ntfs_filesystem(target, dfs, **kwargs)
60
66
 
61
- if is_drive_letter_path(path):
62
- target.fs.mount(path.name[0] + ":", dfs)
67
+ if drive_letter is not None:
68
+ target.fs.mount(drive_letter.lower() + ":", dfs)
63
69
 
64
70
 
65
71
  def find_and_map_dirs(target: Target, path: Path, **kwargs) -> None:
@@ -43,6 +43,8 @@ def find_fs_directories(path: Path) -> tuple[Optional[OperatingSystem], Optional
43
43
  # https://github.com/Velocidex/velociraptor/blob/87368e7cc678144592a1614bb3bbd0a0f900ded9/accessors/ntfs/vss.go#L82
44
44
  if "HarddiskVolumeShadowCopy" in volume.name:
45
45
  vss_volumes.add(volume)
46
+ elif (drive_letter := extract_drive_letter(volume.name)) is not None:
47
+ volumes.add((drive_letter, volume))
46
48
  else:
47
49
  volumes.add(volume)
48
50
 
@@ -54,6 +56,12 @@ def find_fs_directories(path: Path) -> tuple[Optional[OperatingSystem], Optional
54
56
  return None, None
55
57
 
56
58
 
59
+ def extract_drive_letter(name: str) -> Optional[str]:
60
+ # \\.\X: in URL encoding
61
+ if len(name) == 14 and name.startswith("%5C%5C.%5C") and name.endswith("%3A"):
62
+ return name[10].lower()
63
+
64
+
57
65
  class VelociraptorLoader(DirLoader):
58
66
  """Load Rapid7 Velociraptor forensic image files.
59
67
 
@@ -3,10 +3,16 @@
3
3
  from __future__ import print_function
4
4
 
5
5
  import argparse
6
+ import itertools
6
7
  import logging
7
8
 
8
9
  from dissect.target import Target
9
- from dissect.target.exceptions import RegistryError, TargetError
10
+ from dissect.target.exceptions import (
11
+ RegistryError,
12
+ RegistryKeyNotFoundError,
13
+ TargetError,
14
+ )
15
+ from dissect.target.helpers.regutil import RegistryKey
10
16
  from dissect.target.tools.utils import (
11
17
  catch_sigpipe,
12
18
  configure_generic_arguments,
@@ -29,7 +35,8 @@ def main():
29
35
  parser.add_argument("targets", metavar="TARGETS", nargs="+", help="Targets to load")
30
36
  parser.add_argument("-k", "--key", required=True, help="key to query")
31
37
  parser.add_argument("-kv", "--value", help="value to query")
32
- parser.add_argument("-d", "--depth", type=int, const=0, nargs="?", default=1)
38
+ parser.add_argument("-d", "--depth", type=int, const=0, nargs="?", default=1, help="max depth of subkeys to print")
39
+ parser.add_argument("-l", "--length", type=int, default=100, help="max length of key value to print")
33
40
 
34
41
  configure_generic_arguments(parser)
35
42
  args = parser.parse_args()
@@ -38,34 +45,50 @@ def main():
38
45
 
39
46
  try:
40
47
  for target in Target.open_all(args.targets):
48
+ if not target.has_function("registry"):
49
+ target.log.error("Target has no Windows Registry")
50
+ continue
51
+
41
52
  try:
42
- if args.value:
43
- for key in target.registry.keys(args.key):
44
- try:
45
- print(key.value(args.value))
46
- except RegistryError:
47
- continue
48
- else:
53
+ keys = target.registry.keys(args.key)
54
+ first_key = next(keys)
55
+
56
+ print(target)
57
+
58
+ for key in itertools.chain([first_key], keys):
49
59
  try:
50
- print(target)
51
- for key in target.registry.keys(args.key):
52
- recursor(key, args.depth, 0)
60
+ if args.value:
61
+ print(key.value(args.value))
62
+ else:
63
+ recursor(key, args.depth, 0, args.length)
53
64
  except RegistryError:
54
65
  log.exception("Failed to find registry value")
55
- except Exception:
56
- log.exception("Failed to iterate key")
66
+
67
+ except (RegistryKeyNotFoundError, StopIteration):
68
+ target.log.error("Key %r does not exist", args.key)
69
+
70
+ except Exception as e:
71
+ target.log.error("Failed to iterate key: %s", e)
72
+ target.log.debug("", exc_info=e)
57
73
  except TargetError as e:
58
74
  log.error(e)
59
75
  log.debug("", exc_info=e)
60
76
  parser.exit(1)
61
77
 
62
78
 
63
- def recursor(key, depth, indent):
64
- print(" " * indent + f"+ {key.name!r} ({key.ts})")
79
+ def recursor(key: RegistryKey, depth: int, indent: int, max_length: int = 100) -> None:
80
+ class_name = ""
81
+ if key.class_name:
82
+ class_name = f" ({key.class_name})"
83
+
84
+ print(" " * indent + f"+ {key.name!r} ({key.ts})" + class_name)
65
85
 
66
86
  for r in key.values():
67
87
  try:
68
- print(" " * indent + f" - {r.name!r} {repr(r.value)[:100]}")
88
+ value = repr(r.value)
89
+ if len(value) > max_length:
90
+ value = value[:max_length] + "..."
91
+ print(" " * indent + f" - {r.name!r} {value}")
69
92
  except NotImplementedError:
70
93
  continue
71
94
 
@@ -73,7 +96,7 @@ def recursor(key, depth, indent):
73
96
  return
74
97
 
75
98
  for subkey in key.subkeys():
76
- recursor(subkey, depth - 1, indent + 2)
99
+ recursor(subkey, depth - 1, indent + 2, max_length)
77
100
 
78
101
 
79
102
  if __name__ == "__main__":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.16.dev39
3
+ Version: 3.16.dev43
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
@@ -35,7 +35,7 @@ Requires-Dist: flow.record ~=3.14.0
35
35
  Requires-Dist: structlog
36
36
  Provides-Extra: cb
37
37
  Requires-Dist: dissect.target[full] ; extra == 'cb'
38
- Requires-Dist: carbon-black-cloud-sdk-python ~=1.4.3 ; extra == 'cb'
38
+ Requires-Dist: carbon-black-cloud-sdk ~=1.4.3 ; extra == 'cb'
39
39
  Provides-Extra: full
40
40
  Requires-Dist: asn1crypto ; extra == 'full'
41
41
  Requires-Dist: dissect.btrfs <2.0.dev,>=1.0.dev ; extra == 'full'
@@ -48,7 +48,7 @@ dissect/target/helpers/configutil.py,sha256=t_UNvcWuMMT5C1tut_PgTwCnVUodf6RjhfXP
48
48
  dissect/target/helpers/cyber.py,sha256=Ki5oSU0GgQxjgC_yWoeieGP7GOY5blQCzNX7vy7Pgas,16782
49
49
  dissect/target/helpers/descriptor_extensions.py,sha256=uT8GwznfDAiIgMM7JKKOY0PXKMv2c0GCqJTCkWFgops,2605
50
50
  dissect/target/helpers/docs.py,sha256=J5U65Y3yOTqxDEZRCdrEmO63XQCeDzOJea1PwPM6Cyc,5146
51
- dissect/target/helpers/fsutil.py,sha256=Djm7r7gbxMlm7QQagWNeoHd-KoCn3u3JMMRc4TH950Q,19781
51
+ dissect/target/helpers/fsutil.py,sha256=tPyH4RBDqM9QXjamIQaDRLUy3b4dKmfrT6k3ZP01U6Y,19772
52
52
  dissect/target/helpers/hashutil.py,sha256=SD24rcV_y0sBEl7M9T-isjm-VzJvCiTN2BoWMqAOAVI,2160
53
53
  dissect/target/helpers/keychain.py,sha256=wYH0sf7eaxP0bZTo80RF_BQMWulCWmIQ8Tzt9K5TSNQ,3611
54
54
  dissect/target/helpers/lazy.py,sha256=823VtmdWsbJyVZvNWopDhQdqq2i1xtj6b8IKfveboKw,1771
@@ -78,7 +78,7 @@ dissect/target/loaders/ad1.py,sha256=1_VmPZckDzXVvNF-HNtoUZqabnhCKBLUD3vVaitHQ00
78
78
  dissect/target/loaders/asdf.py,sha256=dvPPDBrnz2JPXpCbqsu-NgQWIdVGMOit2KAdhIO1iiQ,972
79
79
  dissect/target/loaders/cb.py,sha256=EGhdytBKBdofTd89juavDZZbmupEZmMBadeUXvVIK20,6612
80
80
  dissect/target/loaders/cyber.py,sha256=Ip2hI7L98ZP7gUZuHQr0GxBdmbTzD-PntXmLJ5KpBuQ,1533
81
- dissect/target/loaders/dir.py,sha256=nEJepNGI4EEP7MX3X15xysH9agKDmlKjfyd1DDulieU,4968
81
+ dissect/target/loaders/dir.py,sha256=Q5oVS48SuI0vA_QKgzWBiAFsQ4aQaW3tr-701vLk3AQ,5245
82
82
  dissect/target/loaders/hyperv.py,sha256=_IOUJEO0BXaCBZ6sjIX0DZTkG9UNW5Vs9VcNHYv073w,5928
83
83
  dissect/target/loaders/itunes.py,sha256=69aMTQiiGYpmD_EYSmf9mO1re8C3jAZIEStmwlMxdAk,13146
84
84
  dissect/target/loaders/kape.py,sha256=t5TfrGLqPeIpUUpXzIl6aHsqXMEGDqJ5YwDCs07DiBA,1237
@@ -102,7 +102,7 @@ dissect/target/loaders/targetd.py,sha256=sfbn2_j3il2G-rPywAoNT5YPtD5KmKkmBv1zrPD
102
102
  dissect/target/loaders/utm.py,sha256=e5x5ZI3HeL0STh4S-CaQb68Rnug4SVZR9zlmHaGFj0M,978
103
103
  dissect/target/loaders/vb.py,sha256=CnQcn7bAkMzIB1y-lWLtPPXdIVsyeDaT6hTZEurjkV4,2072
104
104
  dissect/target/loaders/vbox.py,sha256=8JD7D8iAY9JRvTHsrosp5ZMsZezuLhZ10Zt8sEL7KBI,732
105
- dissect/target/loaders/velociraptor.py,sha256=WPnDIWANIIUPgc-kfXSjXptCQ2pkcy1jdkEydiOvs58,4613
105
+ dissect/target/loaders/velociraptor.py,sha256=FNxZgs_ehmgGO_Giw5oNl7cVOWNqI2nEiPWT4GjF2e0,4955
106
106
  dissect/target/loaders/vma.py,sha256=AAY5-s-nz6wgvmcFkptJD7nNXhpkdf6SqEKVOrJaIKs,644
107
107
  dissect/target/loaders/vmwarevm.py,sha256=1MlKoIuWSwpYmpuLxDuVacvaYHUhAGO1KgZxzrc4fyg,428
108
108
  dissect/target/loaders/vmx.py,sha256=o1rYYKu6ReleqqHf2aeRcNrmoRcngWZNhz1h7GlmggQ,962
@@ -317,7 +317,7 @@ dissect/target/tools/info.py,sha256=3smHr8I71yj3kCjsQ5nXkOHI9T_N8UwvkVa1CNOxB-s,
317
317
  dissect/target/tools/logging.py,sha256=5ZnumtMWLyslxfrUGZ4ntRyf3obOOhmn8SBjKfdLcEg,4174
318
318
  dissect/target/tools/mount.py,sha256=L_0tSmiBdW4aSaF0vXjB0bAkTC0kmT2N1hrbW6s5Jow,3254
319
319
  dissect/target/tools/query.py,sha256=1LbvUKSmXOCMb4xqP3t86JkOgFzKlc7mLCqcczfLht8,16018
320
- dissect/target/tools/reg.py,sha256=tII0MLqJ-3lOt7jE-zHUDqYrk0P4euPjiSS_99FT6LE,2378
320
+ dissect/target/tools/reg.py,sha256=FDsiBBDxjWVUBTRj8xn82vZe-J_d9piM-TKS3PHZCcM,3193
321
321
  dissect/target/tools/shell.py,sha256=EBRNKiIV3ljaXKAXraA6DmrIw8Cy5h9irAuwlblP3zo,43251
322
322
  dissect/target/tools/utils.py,sha256=bhVZ3-8YynpHkBl4m1T4IpSpCArAXnEjjYwAFGW5JPg,10595
323
323
  dissect/target/tools/dump/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -332,10 +332,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
332
332
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
333
333
  dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
334
334
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
335
- dissect.target-3.16.dev39.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
336
- dissect.target-3.16.dev39.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
337
- dissect.target-3.16.dev39.dist-info/METADATA,sha256=ngLz4XeexsGKv4urTocePElt3tx1Jpc0yxVHs1FcGWU,11107
338
- dissect.target-3.16.dev39.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
339
- dissect.target-3.16.dev39.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
340
- dissect.target-3.16.dev39.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
341
- dissect.target-3.16.dev39.dist-info/RECORD,,
335
+ dissect.target-3.16.dev43.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
336
+ dissect.target-3.16.dev43.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
337
+ dissect.target-3.16.dev43.dist-info/METADATA,sha256=k_mmSMwlIKc86B11l-UAys9JHWtSfbicJtUob1FmEfE,11100
338
+ dissect.target-3.16.dev43.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
339
+ dissect.target-3.16.dev43.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
340
+ dissect.target-3.16.dev43.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
341
+ dissect.target-3.16.dev43.dist-info/RECORD,,