dissect.target 3.19.dev32__py3-none-any.whl → 3.19.dev34__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- dissect/target/helpers/config.py +22 -7
- dissect/target/helpers/loaderutil.py +26 -7
- dissect/target/target.py +3 -2
- dissect/target/tools/shell.py +34 -2
- {dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/METADATA +1 -1
- {dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/RECORD +11 -11
- {dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/LICENSE +0 -0
- {dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/WHEEL +0 -0
- {dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/top_level.txt +0 -0
dissect/target/helpers/config.py
CHANGED
@@ -1,27 +1,35 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import ast
|
2
4
|
import importlib.machinery
|
3
5
|
import importlib.util
|
4
6
|
import logging
|
5
7
|
from pathlib import Path
|
6
8
|
from types import ModuleType
|
7
|
-
from typing import Optional, Union
|
8
9
|
|
9
10
|
log = logging.getLogger(__name__)
|
10
11
|
|
11
12
|
CONFIG_NAME = ".targetcfg.py"
|
12
13
|
|
13
14
|
|
14
|
-
def load(
|
15
|
+
def load(paths: list[Path | str] | Path | str | None) -> ModuleType:
|
16
|
+
"""Attempt to load one configuration from the provided path(s)."""
|
17
|
+
|
18
|
+
if isinstance(paths, Path) or isinstance(paths, str):
|
19
|
+
paths = [paths]
|
20
|
+
|
15
21
|
config_spec = importlib.machinery.ModuleSpec("config", None)
|
16
22
|
config = importlib.util.module_from_spec(config_spec)
|
17
|
-
config_file = _find_config_file(
|
23
|
+
config_file = _find_config_file(paths)
|
24
|
+
|
18
25
|
if config_file:
|
19
26
|
config_values = _parse_ast(config_file.read_bytes())
|
20
27
|
config.__dict__.update(config_values)
|
28
|
+
|
21
29
|
return config
|
22
30
|
|
23
31
|
|
24
|
-
def _parse_ast(code: str) -> dict[str,
|
32
|
+
def _parse_ast(code: str) -> dict[str, str | int]:
|
25
33
|
# Only allow basic value assignments for backwards compatibility
|
26
34
|
obj = {}
|
27
35
|
|
@@ -49,15 +57,19 @@ def _parse_ast(code: str) -> dict[str, Union[str, int]]:
|
|
49
57
|
return obj
|
50
58
|
|
51
59
|
|
52
|
-
def _find_config_file(
|
53
|
-
"""Find a config file anywhere in the given path and return it.
|
60
|
+
def _find_config_file(paths: list[Path | str] | None) -> Path | None:
|
61
|
+
"""Find a config file anywhere in the given path(s) and return it.
|
54
62
|
|
55
63
|
This algorithm allows parts of the path to not exist or the last part to be a filename.
|
56
64
|
It also does not look in the root directory ('/') for config files.
|
57
65
|
"""
|
58
66
|
|
67
|
+
if not paths:
|
68
|
+
return
|
69
|
+
|
59
70
|
config_file = None
|
60
|
-
|
71
|
+
|
72
|
+
for path in paths:
|
61
73
|
path = Path(path)
|
62
74
|
cur_path = path.absolute()
|
63
75
|
|
@@ -69,4 +81,7 @@ def _find_config_file(path: Optional[Union[Path, str]]) -> Optional[Path]:
|
|
69
81
|
config_file = cur_config
|
70
82
|
cur_path = cur_path.parent
|
71
83
|
|
84
|
+
if config_file:
|
85
|
+
break
|
86
|
+
|
72
87
|
return config_file
|
@@ -5,7 +5,7 @@ import re
|
|
5
5
|
import urllib
|
6
6
|
from os import PathLike
|
7
7
|
from pathlib import Path
|
8
|
-
from typing import TYPE_CHECKING, BinaryIO
|
8
|
+
from typing import TYPE_CHECKING, BinaryIO
|
9
9
|
|
10
10
|
from dissect.target.exceptions import FileNotFoundError
|
11
11
|
from dissect.target.filesystem import Filesystem
|
@@ -42,12 +42,31 @@ def add_virtual_ntfs_filesystem(
|
|
42
42
|
fh_sds = _try_open(fs, sds_path)
|
43
43
|
|
44
44
|
if any([fh_boot, fh_mft]):
|
45
|
-
ntfs =
|
46
|
-
target.filesystems.add(ntfs)
|
47
|
-
fs.ntfs = ntfs.ntfs
|
45
|
+
ntfs = None
|
48
46
|
|
49
|
-
|
50
|
-
|
47
|
+
try:
|
48
|
+
ntfs = NtfsFilesystem(boot=fh_boot, mft=fh_mft, usnjrnl=fh_usnjrnl, sds=fh_sds)
|
49
|
+
except Exception as e:
|
50
|
+
if fh_boot:
|
51
|
+
log.warning("Failed to load NTFS filesystem from %s, retrying without $Boot file", fs)
|
52
|
+
log.debug("", exc_info=e)
|
53
|
+
|
54
|
+
try:
|
55
|
+
# Try once more without the $Boot file
|
56
|
+
ntfs = NtfsFilesystem(mft=fh_mft, usnjrnl=fh_usnjrnl, sds=fh_sds)
|
57
|
+
except Exception:
|
58
|
+
log.warning("Failed to load NTFS filesystem from %s without $Boot file, skipping", fs)
|
59
|
+
return
|
60
|
+
|
61
|
+
# Only add it if we have a valid NTFS with an MFT
|
62
|
+
if ntfs and ntfs.ntfs.mft:
|
63
|
+
target.filesystems.add(ntfs)
|
64
|
+
fs.ntfs = ntfs.ntfs
|
65
|
+
else:
|
66
|
+
log.warning("Opened NTFS filesystem from %s but could not find $MFT, skipping", fs)
|
67
|
+
|
68
|
+
|
69
|
+
def _try_open(fs: Filesystem, path: str) -> BinaryIO | None:
|
51
70
|
paths = [path] if not isinstance(path, list) else path
|
52
71
|
|
53
72
|
for path in paths:
|
@@ -61,7 +80,7 @@ def _try_open(fs: Filesystem, path: str) -> BinaryIO:
|
|
61
80
|
pass
|
62
81
|
|
63
82
|
|
64
|
-
def extract_path_info(path:
|
83
|
+
def extract_path_info(path: str | Path) -> tuple[Path, urllib.parse.ParseResult | None]:
|
65
84
|
"""
|
66
85
|
Extracts a ParseResult from a path if it has
|
67
86
|
a scheme and adjusts the path if necessary.
|
dissect/target/target.py
CHANGED
@@ -87,9 +87,10 @@ class Target:
|
|
87
87
|
self._applied = False
|
88
88
|
|
89
89
|
try:
|
90
|
-
self._config = config.load(self.path)
|
90
|
+
self._config = config.load([self.path, os.getcwd()])
|
91
91
|
except Exception as e:
|
92
|
-
self.log.
|
92
|
+
self.log.warning("Error loading config file: %s", self.path)
|
93
|
+
self.log.debug("", exc_info=e)
|
93
94
|
self._config = config.load(None) # This loads an empty config.
|
94
95
|
|
95
96
|
# Fill the disks and/or volumes and/or filesystems and apply() will
|
dissect/target/tools/shell.py
CHANGED
@@ -58,6 +58,7 @@ try:
|
|
58
58
|
except ImportError:
|
59
59
|
# Readline is not available on Windows
|
60
60
|
log.warning("Readline module is not available")
|
61
|
+
readline = None
|
61
62
|
|
62
63
|
# ['mode', 'addr', 'dev', 'nlink', 'uid', 'gid', 'size', 'atime', 'mtime', 'ctime']
|
63
64
|
STAT_TEMPLATE = """ File: {path} {symlink}
|
@@ -111,12 +112,43 @@ class TargetCmd(cmd.Cmd):
|
|
111
112
|
|
112
113
|
CMD_PREFIX = "cmd_"
|
113
114
|
|
115
|
+
DEFAULT_HISTFILE = "~/.dissect_history"
|
116
|
+
DEFAULT_HISTFILESIZE = 10_000
|
117
|
+
DEFAULT_HISTDIR = None
|
118
|
+
DEFAULT_HISTDIRFMT = ".dissect_history_{uid}_{target}"
|
119
|
+
|
114
120
|
def __init__(self, target: Target):
|
115
121
|
cmd.Cmd.__init__(self)
|
116
122
|
self.target = target
|
117
123
|
self.debug = False
|
118
124
|
self.identchars += "."
|
119
125
|
|
126
|
+
self.histfilesize = getattr(target._config, "HISTFILESIZE", self.DEFAULT_HISTFILESIZE)
|
127
|
+
self.histdir = getattr(target._config, "HISTDIR", self.DEFAULT_HISTDIR)
|
128
|
+
|
129
|
+
if self.histdir:
|
130
|
+
self.histdirfmt = getattr(target._config, "HISTDIRFMT", self.DEFAULT_HISTDIRFMT)
|
131
|
+
self.histfile = pathlib.Path(self.histdir).resolve() / pathlib.Path(
|
132
|
+
self.histdirfmt.format(uid=os.getuid(), target=target.name)
|
133
|
+
)
|
134
|
+
else:
|
135
|
+
self.histfile = pathlib.Path(getattr(target._config, "HISTFILE", self.DEFAULT_HISTFILE)).expanduser()
|
136
|
+
|
137
|
+
def preloop(self) -> None:
|
138
|
+
if readline and self.histfile.exists():
|
139
|
+
try:
|
140
|
+
readline.read_history_file(self.histfile)
|
141
|
+
except Exception as e:
|
142
|
+
log.debug("Error reading history file: %s", e)
|
143
|
+
|
144
|
+
def postloop(self) -> None:
|
145
|
+
if readline:
|
146
|
+
readline.set_history_length(self.histfilesize)
|
147
|
+
try:
|
148
|
+
readline.write_history_file(self.histfile)
|
149
|
+
except Exception as e:
|
150
|
+
log.debug("Error writing history file: %s", e)
|
151
|
+
|
120
152
|
def __getattr__(self, attr: str) -> Any:
|
121
153
|
if attr.startswith("help_"):
|
122
154
|
_, _, command = attr.partition("_")
|
@@ -1241,10 +1273,11 @@ def run_cli(cli: cmd.Cmd) -> None:
|
|
1241
1273
|
# Print an empty newline on exit
|
1242
1274
|
print()
|
1243
1275
|
return
|
1276
|
+
|
1244
1277
|
except KeyboardInterrupt:
|
1245
1278
|
# Add a line when pressing ctrl+c, so the next one starts at a new line
|
1246
1279
|
print()
|
1247
|
-
|
1280
|
+
|
1248
1281
|
except Exception as e:
|
1249
1282
|
if cli.debug:
|
1250
1283
|
log.exception(e)
|
@@ -1252,7 +1285,6 @@ def run_cli(cli: cmd.Cmd) -> None:
|
|
1252
1285
|
log.info(e)
|
1253
1286
|
print(f"*** Unhandled error: {e}")
|
1254
1287
|
print("If you wish to see the full debug trace, enable debug mode.")
|
1255
|
-
pass
|
1256
1288
|
|
1257
1289
|
|
1258
1290
|
@catch_sigpipe
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.19.
|
3
|
+
Version: 3.19.dev34
|
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
|
@@ -5,7 +5,7 @@ dissect/target/filesystem.py,sha256=G1gbOUpnQZyovubYGEUKgaDV0eHH5vE83-0gTc5PZAM,
|
|
5
5
|
dissect/target/loader.py,sha256=I8WNzDA0SMy42F7zfyBcSKj_VKNv64213WUvtGZ77qE,7374
|
6
6
|
dissect/target/plugin.py,sha256=HAN8maaDt-Rlqt8Rr1IW7gXQpzNQZjCVz-i4aSPphSw,48677
|
7
7
|
dissect/target/report.py,sha256=06uiP4MbNI8cWMVrC1SasNS-Yg6ptjVjckwj8Yhe0Js,7958
|
8
|
-
dissect/target/target.py,sha256=
|
8
|
+
dissect/target/target.py,sha256=nqd5OuVTwYR7XSzlMp7SHQoRCgZD_Z7QshnEEKcX-tw,32426
|
9
9
|
dissect/target/volume.py,sha256=aQZAJiny8jjwkc9UtwIRwy7nINXjCxwpO-_UDfh6-BA,15801
|
10
10
|
dissect/target/containers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
dissect/target/containers/asdf.py,sha256=DJp0QEFwUjy2MFwKYcYqIR_BS1fQT1Yi9Kcmqt0aChM,1366
|
@@ -45,7 +45,7 @@ dissect/target/filesystems/xfs.py,sha256=kIyFGKYlyFYC7H3jaEv-lNKtBW4ZkD92H0WpfGc
|
|
45
45
|
dissect/target/filesystems/zip.py,sha256=WT1bQhzX_1MXXVZTKrJniae4xqRqMZ8FsfbvhgGQRTQ,4462
|
46
46
|
dissect/target/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
47
|
dissect/target/helpers/cache.py,sha256=TXlJBdFRz6V9zKs903am4Yawr0maYw5kZY0RqklDQJM,8568
|
48
|
-
dissect/target/helpers/config.py,sha256=
|
48
|
+
dissect/target/helpers/config.py,sha256=RMHnIuKJHINHiLrvKN3EyA0jFA1o6-pbeaycG8Pgrp8,2596
|
49
49
|
dissect/target/helpers/configutil.py,sha256=AEnkMQ0e6PncvCqGa-ACzBQWQBhMGBCzO5qzGJtRu60,27644
|
50
50
|
dissect/target/helpers/cyber.py,sha256=WnJlk-HqAETmDAgLq92JPxyDLxvzSoFV_WrO-odVKBI,16805
|
51
51
|
dissect/target/helpers/descriptor_extensions.py,sha256=uT8GwznfDAiIgMM7JKKOY0PXKMv2c0GCqJTCkWFgops,2605
|
@@ -54,7 +54,7 @@ dissect/target/helpers/fsutil.py,sha256=tPyH4RBDqM9QXjamIQaDRLUy3b4dKmfrT6k3ZP01
|
|
54
54
|
dissect/target/helpers/hashutil.py,sha256=bYAGEjyYyxuCTziO4kCx6srzY1Cm-PXmayRRcxt5ca4,1061
|
55
55
|
dissect/target/helpers/keychain.py,sha256=wYH0sf7eaxP0bZTo80RF_BQMWulCWmIQ8Tzt9K5TSNQ,3611
|
56
56
|
dissect/target/helpers/lazy.py,sha256=823VtmdWsbJyVZvNWopDhQdqq2i1xtj6b8IKfveboKw,1771
|
57
|
-
dissect/target/helpers/loaderutil.py,sha256=
|
57
|
+
dissect/target/helpers/loaderutil.py,sha256=4cS0RKGgsljQYYc5uGzmnWJ_NXt7QfWJ1jvtEINZmdE,3415
|
58
58
|
dissect/target/helpers/localeutil.py,sha256=Y4Fh4jDSGfm5356xSLMriUCN8SZP_FAHg_iodkAxNq4,1504
|
59
59
|
dissect/target/helpers/mount.py,sha256=JxhUYyEbDnHfzPpfuWy4nV9OwCJPoDSGdHHNiyvd_l0,3949
|
60
60
|
dissect/target/helpers/mui.py,sha256=i-7XoHbu4WO2fYapK9yGAMW04rFlgRispknc1KQIS5Q,22258
|
@@ -331,7 +331,7 @@ dissect/target/tools/logging.py,sha256=5ZnumtMWLyslxfrUGZ4ntRyf3obOOhmn8SBjKfdLc
|
|
331
331
|
dissect/target/tools/mount.py,sha256=L_0tSmiBdW4aSaF0vXjB0bAkTC0kmT2N1hrbW6s5Jow,3254
|
332
332
|
dissect/target/tools/query.py,sha256=ONHu2FVomLccikb84qBrlhNmEfRoHYFQMcahk_y2c9A,15580
|
333
333
|
dissect/target/tools/reg.py,sha256=FDsiBBDxjWVUBTRj8xn82vZe-J_d9piM-TKS3PHZCcM,3193
|
334
|
-
dissect/target/tools/shell.py,sha256=
|
334
|
+
dissect/target/tools/shell.py,sha256=sjoc4nI9fsU5ZG7nDPNZvE-RtIPTwREbVdbg8WA3XTo,46442
|
335
335
|
dissect/target/tools/utils.py,sha256=sQizexY3ui5vmWw4KOBLg5ecK3TPFjD-uxDqRn56ZTY,11304
|
336
336
|
dissect/target/tools/yara.py,sha256=70k-2VMulf1EdkX03nCACzejaOEcsFHOyX-4E40MdQU,2044
|
337
337
|
dissect/target/tools/dump/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -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.dev34.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
350
|
+
dissect.target-3.19.dev34.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
351
|
+
dissect.target-3.19.dev34.dist-info/METADATA,sha256=fiUYaR4jBceVkr1ddarm8Xyn0sU8feK-AvW5l7JAbXU,12719
|
352
|
+
dissect.target-3.19.dev34.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
353
|
+
dissect.target-3.19.dev34.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
|
354
|
+
dissect.target-3.19.dev34.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
355
|
+
dissect.target-3.19.dev34.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.19.dev32.dist-info → dissect.target-3.19.dev34.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|