dissect.target 3.19.dev21__py3-none-any.whl → 3.19.dev23__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/helpers/network_managers.py +22 -7
- dissect/target/plugins/filesystem/yara.py +146 -23
- dissect/target/plugins/os/unix/linux/_os.py +1 -1
- dissect/target/tools/yara.py +61 -0
- {dissect.target-3.19.dev21.dist-info → dissect.target-3.19.dev23.dist-info}/METADATA +1 -1
- {dissect.target-3.19.dev21.dist-info → dissect.target-3.19.dev23.dist-info}/RECORD +11 -10
- {dissect.target-3.19.dev21.dist-info → dissect.target-3.19.dev23.dist-info}/entry_points.txt +1 -0
- {dissect.target-3.19.dev21.dist-info → dissect.target-3.19.dev23.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.19.dev21.dist-info → dissect.target-3.19.dev23.dist-info}/LICENSE +0 -0
- {dissect.target-3.19.dev21.dist-info → dissect.target-3.19.dev23.dist-info}/WHEEL +0 -0
- {dissect.target-3.19.dev21.dist-info → dissect.target-3.19.dev23.dist-info}/top_level.txt +0 -0
@@ -7,12 +7,14 @@ from configparser import ConfigParser, MissingSectionHeaderError
|
|
7
7
|
from io import StringIO
|
8
8
|
from itertools import chain
|
9
9
|
from re import compile, sub
|
10
|
-
from typing import Any, Callable, Iterable, Match, Optional
|
10
|
+
from typing import Any, Callable, Iterable, Iterator, Match, Optional
|
11
11
|
|
12
12
|
from defusedxml import ElementTree
|
13
13
|
|
14
14
|
from dissect.target.exceptions import PluginError
|
15
15
|
from dissect.target.helpers.fsutil import TargetPath
|
16
|
+
from dissect.target.plugins.os.unix.log.journal import JournalRecord
|
17
|
+
from dissect.target.plugins.os.unix.log.messages import MessagesRecord
|
16
18
|
from dissect.target.target import Target
|
17
19
|
|
18
20
|
log = logging.getLogger(__name__)
|
@@ -509,14 +511,15 @@ class LinuxNetworkManager:
|
|
509
511
|
return values
|
510
512
|
|
511
513
|
|
512
|
-
def parse_unix_dhcp_log_messages(target) ->
|
514
|
+
def parse_unix_dhcp_log_messages(target: Target, iter_all: bool = False) -> set[str]:
|
513
515
|
"""Parse local syslog, journal and cloud init-log files for DHCP lease IPs.
|
514
516
|
|
515
517
|
Args:
|
516
518
|
target: Target to discover and obtain network information from.
|
519
|
+
iter_all: Parse limited amount of journal messages (first 10000) or all of them.
|
517
520
|
|
518
521
|
Returns:
|
519
|
-
|
522
|
+
A set of found DHCP IP addresses.
|
520
523
|
"""
|
521
524
|
ips = set()
|
522
525
|
messages = set()
|
@@ -530,9 +533,19 @@ def parse_unix_dhcp_log_messages(target) -> list[str]:
|
|
530
533
|
if not messages:
|
531
534
|
target.log.warning(f"Could not search for DHCP leases using {log_func}: No log entries found.")
|
532
535
|
|
533
|
-
|
536
|
+
def records_enumerate(iterable: Iterable) -> Iterator[tuple[int, JournalRecord | MessagesRecord]]:
|
537
|
+
count = 0
|
538
|
+
for rec in iterable:
|
539
|
+
if rec._desc.name == "linux/log/journal":
|
540
|
+
count += 1
|
541
|
+
yield count, rec
|
542
|
+
|
543
|
+
for count, record in records_enumerate(messages):
|
534
544
|
line = record.message
|
535
545
|
|
546
|
+
if not line:
|
547
|
+
continue
|
548
|
+
|
536
549
|
# Ubuntu cloud-init
|
537
550
|
if "Received dhcp lease on" in line:
|
538
551
|
interface, ip, netmask = re.search(r"Received dhcp lease on (\w{0,}) for (\S+)\/(\S+)", line).groups()
|
@@ -576,9 +589,11 @@ def parse_unix_dhcp_log_messages(target) -> list[str]:
|
|
576
589
|
ips.add(ip)
|
577
590
|
continue
|
578
591
|
|
579
|
-
#
|
580
|
-
#
|
581
|
-
if
|
592
|
+
# The journal parser is relatively slow, so we stop when we have read 10000 journal entries,
|
593
|
+
# or if we have found at least one ip address. When `iter_all` is `True` we continue searching.
|
594
|
+
if not iter_all and (ips or count > 10_000):
|
595
|
+
if not ips:
|
596
|
+
target.log.warning("No DHCP IP addresses found in first 10000 journal entries.")
|
582
597
|
break
|
583
598
|
|
584
599
|
return ips
|
@@ -1,14 +1,27 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import hashlib
|
4
|
+
import logging
|
5
|
+
from io import BytesIO
|
1
6
|
from pathlib import Path
|
7
|
+
from typing import Iterator
|
8
|
+
|
9
|
+
from dissect.target.helpers import hashutil
|
2
10
|
|
3
11
|
try:
|
4
12
|
import yara
|
13
|
+
|
14
|
+
HAS_YARA = True
|
15
|
+
|
5
16
|
except ImportError:
|
6
|
-
|
17
|
+
HAS_YARA = False
|
7
18
|
|
8
|
-
from dissect.target.exceptions import FileNotFoundError
|
19
|
+
from dissect.target.exceptions import FileNotFoundError, UnsupportedPluginError
|
9
20
|
from dissect.target.helpers.record import TargetRecordDescriptor
|
10
21
|
from dissect.target.plugin import Plugin, arg, export
|
11
22
|
|
23
|
+
log = logging.getLogger(__name__)
|
24
|
+
|
12
25
|
YaraMatchRecord = TargetRecordDescriptor(
|
13
26
|
"filesystem/yara/match",
|
14
27
|
[
|
@@ -16,48 +29,158 @@ YaraMatchRecord = TargetRecordDescriptor(
|
|
16
29
|
("digest", "digest"),
|
17
30
|
("string", "rule"),
|
18
31
|
("string[]", "tags"),
|
32
|
+
("string", "namespace"),
|
19
33
|
],
|
20
34
|
)
|
21
35
|
|
36
|
+
DEFAULT_MAX_SCAN_SIZE = 10 * 1024 * 1024
|
37
|
+
|
22
38
|
|
23
39
|
class YaraPlugin(Plugin):
|
24
40
|
"""Plugin to scan files against a local YARA rules file."""
|
25
41
|
|
26
|
-
DEFAULT_MAX_SIZE = 10 * 1024 * 1024
|
27
|
-
|
28
42
|
def check_compatible(self) -> None:
|
29
|
-
|
43
|
+
if not HAS_YARA:
|
44
|
+
raise UnsupportedPluginError("Please install 'yara-python' to use the yara plugin.")
|
30
45
|
|
31
|
-
@arg("
|
32
|
-
@arg("--
|
33
|
-
@arg("
|
46
|
+
@arg("-r", "--rules", required=True, nargs="*", help="path(s) to YARA rule file(s) or folder(s)")
|
47
|
+
@arg("-p", "--path", default="/", help="path on target(s) to recursively scan")
|
48
|
+
@arg("-m", "--max-size", default=DEFAULT_MAX_SCAN_SIZE, help="maximum file size in bytes to scan")
|
49
|
+
@arg("-c", "--check", default=False, action="store_true", help="check if every YARA rule is valid")
|
34
50
|
@export(record=YaraMatchRecord)
|
35
|
-
def yara(
|
36
|
-
|
51
|
+
def yara(
|
52
|
+
self,
|
53
|
+
rules: list[str | Path],
|
54
|
+
path: str = "/",
|
55
|
+
max_size: int = DEFAULT_MAX_SCAN_SIZE,
|
56
|
+
check: bool = False,
|
57
|
+
) -> Iterator[YaraMatchRecord]:
|
58
|
+
"""Scan files inside the target up to a given maximum size with YARA rule file(s).
|
59
|
+
|
60
|
+
Args:
|
61
|
+
rules: ``list`` of strings or ``Path`` objects pointing to rule files to use.
|
62
|
+
path: ``string`` of absolute target path to scan.
|
63
|
+
max_size: Files larger than this size will not be scanned.
|
64
|
+
check: Check if provided rules are valid, only compiles valid rules.
|
37
65
|
|
38
|
-
|
39
|
-
|
66
|
+
Returns:
|
67
|
+
Iterator yields ``YaraMatchRecord``.
|
40
68
|
"""
|
41
69
|
|
42
|
-
|
70
|
+
compiled_rules = process_rules(rules, check)
|
43
71
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
72
|
+
if not rules:
|
73
|
+
self.target.log.error("No working rules found in '%s'", ",".join(rules))
|
74
|
+
return
|
75
|
+
|
76
|
+
if hasattr(compiled_rules, "warnings") and (num_warns := len(compiled_rules.warnings)) > 0:
|
77
|
+
self.target.log.warning("YARA generated %s warnings while compiling rules", num_warns)
|
78
|
+
for warning in compiled_rules.warnings:
|
79
|
+
self.target.log.debug(warning)
|
80
|
+
|
81
|
+
self.target.log.warning("Will not scan files larger than %s MB", max_size // 1024 // 1024)
|
82
|
+
|
83
|
+
for _, _, files in self.target.fs.walk_ext(path):
|
84
|
+
for file in files:
|
48
85
|
try:
|
49
|
-
if
|
86
|
+
if file_size := file.stat().st_size > max_size:
|
87
|
+
self.target.log.debug(
|
88
|
+
"Skipping file '%s' as it is larger than %s bytes (size is %s)", file, file_size, max_size
|
89
|
+
)
|
50
90
|
continue
|
51
91
|
|
52
|
-
|
92
|
+
buf = file.open().read()
|
93
|
+
for match in compiled_rules.match(data=buf):
|
53
94
|
yield YaraMatchRecord(
|
54
|
-
path=path,
|
55
|
-
digest=
|
95
|
+
path=self.target.fs.path(file.path),
|
96
|
+
digest=hashutil.common(BytesIO(buf)),
|
56
97
|
rule=match.rule,
|
57
98
|
tags=match.tags,
|
99
|
+
namespace=match.namespace,
|
58
100
|
_target=self.target,
|
59
101
|
)
|
102
|
+
|
60
103
|
except FileNotFoundError:
|
61
104
|
continue
|
62
|
-
except
|
63
|
-
self.target.log.
|
105
|
+
except RuntimeWarning as e:
|
106
|
+
self.target.log.warning("Runtime warning while scanning file '%s': %s", file, e)
|
107
|
+
except Exception as e:
|
108
|
+
self.target.log.error("Exception scanning file '%s'", file)
|
109
|
+
self.target.log.debug("", exc_info=e)
|
110
|
+
|
111
|
+
|
112
|
+
def process_rules(paths: list[str | Path], check: bool = False) -> yara.Rules | None:
|
113
|
+
"""Generate compiled YARA rules from the given path(s).
|
114
|
+
|
115
|
+
Provide path to one (compiled) YARA file or directory containing YARA files.
|
116
|
+
|
117
|
+
Args:
|
118
|
+
paths: Path to file(s) or folder(s) containing YARA files.
|
119
|
+
check: Attempt to compile every rule file before appending to rules.
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
Compiled YARA rules or None.
|
123
|
+
"""
|
124
|
+
files = set()
|
125
|
+
compiled_rules = None
|
126
|
+
|
127
|
+
for rules_path in paths:
|
128
|
+
if isinstance(rules_path, str):
|
129
|
+
rules_path = Path(rules_path)
|
130
|
+
|
131
|
+
if not rules_path.exists():
|
132
|
+
log.warning("File %s does not exist!", rules_path)
|
133
|
+
continue
|
134
|
+
|
135
|
+
if rules_path.is_dir():
|
136
|
+
for file in rules_path.rglob("*"):
|
137
|
+
if not file.is_file():
|
138
|
+
continue
|
139
|
+
files.add(file)
|
140
|
+
else:
|
141
|
+
files.add(rules_path)
|
142
|
+
|
143
|
+
for file in set(files):
|
144
|
+
with file.open("rb") as fh:
|
145
|
+
magic = fh.read(4)
|
146
|
+
|
147
|
+
if magic == b"YARA":
|
148
|
+
if len(files) > 1:
|
149
|
+
log.error("Providing multiple compiled YARA files is not supported. Did not add %s", file)
|
150
|
+
continue
|
151
|
+
else:
|
152
|
+
log.info("Adding single compiled YARA file %s", file)
|
153
|
+
compiled_rules = compile_yara(file, is_compiled=True)
|
154
|
+
break
|
155
|
+
|
156
|
+
elif check and not is_valid_yara({"check_namespace": file}):
|
157
|
+
log.warning("File %s contains invalid rule(s)!", file)
|
158
|
+
files.remove(file)
|
159
|
+
continue
|
160
|
+
|
161
|
+
if files and not compiled_rules:
|
162
|
+
try:
|
163
|
+
compiled_rules = compile_yara({hashlib.md5(file.as_posix().encode()).hexdigest(): file for file in files})
|
164
|
+
except yara.Error as e:
|
165
|
+
log.error("Failed to compile YARA file(s): %s", e)
|
166
|
+
|
167
|
+
return compiled_rules
|
168
|
+
|
169
|
+
|
170
|
+
def compile_yara(files: dict[str, Path] | Path, is_compiled: bool = False) -> yara.Rules | None:
|
171
|
+
"""Compile or load the given YARA file(s) to rules."""
|
172
|
+
if is_compiled and isinstance(files, Path):
|
173
|
+
return yara.load(files.as_posix())
|
174
|
+
else:
|
175
|
+
return yara.compile(filepaths={ns: Path(path).as_posix() for ns, path in files.items()})
|
176
|
+
|
177
|
+
|
178
|
+
def is_valid_yara(files: dict[str, Path] | Path, is_compiled: bool = False) -> bool:
|
179
|
+
"""Determine if the given YARA file(s) compile without errors or warnings."""
|
180
|
+
try:
|
181
|
+
compile_yara(files, is_compiled)
|
182
|
+
return True
|
183
|
+
|
184
|
+
except (yara.SyntaxError, yara.WarningError, yara.Error) as e:
|
185
|
+
log.debug("Rule file(s) '%s' invalid: %s", files, e)
|
186
|
+
return False
|
@@ -41,7 +41,7 @@ class LinuxPlugin(UnixPlugin, LinuxNetworkManager):
|
|
41
41
|
for ip in ip_set:
|
42
42
|
ips.append(ip)
|
43
43
|
|
44
|
-
for ip in parse_unix_dhcp_log_messages(self.target):
|
44
|
+
for ip in parse_unix_dhcp_log_messages(self.target, iter_all=False):
|
45
45
|
if ip not in ips:
|
46
46
|
ips.append(ip)
|
47
47
|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
import argparse
|
4
|
+
import logging
|
5
|
+
|
6
|
+
from dissect.target import Target
|
7
|
+
from dissect.target.exceptions import TargetError
|
8
|
+
from dissect.target.plugins.filesystem.yara import HAS_YARA, YaraPlugin
|
9
|
+
from dissect.target.tools.query import record_output
|
10
|
+
from dissect.target.tools.utils import (
|
11
|
+
catch_sigpipe,
|
12
|
+
configure_generic_arguments,
|
13
|
+
process_generic_arguments,
|
14
|
+
)
|
15
|
+
|
16
|
+
log = logging.getLogger(__name__)
|
17
|
+
|
18
|
+
|
19
|
+
@catch_sigpipe
|
20
|
+
def main():
|
21
|
+
help_formatter = argparse.ArgumentDefaultsHelpFormatter
|
22
|
+
parser = argparse.ArgumentParser(
|
23
|
+
description="target-yara",
|
24
|
+
fromfile_prefix_chars="@",
|
25
|
+
formatter_class=help_formatter,
|
26
|
+
)
|
27
|
+
|
28
|
+
parser.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to load")
|
29
|
+
parser.add_argument("-s", "--strings", default=False, action="store_true", help="print output as string")
|
30
|
+
|
31
|
+
for args, kwargs in getattr(YaraPlugin.yara, "__args__", []):
|
32
|
+
parser.add_argument(*args, **kwargs)
|
33
|
+
|
34
|
+
configure_generic_arguments(parser)
|
35
|
+
|
36
|
+
args = parser.parse_args()
|
37
|
+
process_generic_arguments(args)
|
38
|
+
|
39
|
+
if not HAS_YARA:
|
40
|
+
log.error("yara-python is not installed: pip install yara-python")
|
41
|
+
parser.exit(1)
|
42
|
+
|
43
|
+
if not args.targets:
|
44
|
+
log.error("No targets provided")
|
45
|
+
parser.exit(1)
|
46
|
+
|
47
|
+
try:
|
48
|
+
for target in Target.open_all(args.targets):
|
49
|
+
target.log.info("Scanning target")
|
50
|
+
rs = record_output(args.strings, False)
|
51
|
+
for record in target.yara(args.rules, args.path, args.max_size, args.check):
|
52
|
+
rs.write(record)
|
53
|
+
|
54
|
+
except TargetError as e:
|
55
|
+
log.error(e)
|
56
|
+
log.debug("", exc_info=e)
|
57
|
+
parser.exit(1)
|
58
|
+
|
59
|
+
|
60
|
+
if __name__ == "__main__":
|
61
|
+
main()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.19.
|
3
|
+
Version: 3.19.dev23
|
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
|
@@ -58,7 +58,7 @@ dissect/target/helpers/loaderutil.py,sha256=kiyMWra_gVxfNSGwLlgxLcuuqAYuCMDc5NiC
|
|
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
|
61
|
-
dissect/target/helpers/network_managers.py,sha256=
|
61
|
+
dissect/target/helpers/network_managers.py,sha256=ByBSe2K3c8hgQC6dokcf-hHdmPcD8PmrOj0xs1C3yhs,25743
|
62
62
|
dissect/target/helpers/polypath.py,sha256=h8p7m_OCNiQljGwoZh5Aflr9H2ot6CZr6WKq1OSw58o,2175
|
63
63
|
dissect/target/helpers/protobuf.py,sha256=b4DsnqrRLrefcDjx7rQno-_LBcwtJXxuKf5RdOegzfE,1537
|
64
64
|
dissect/target/helpers/record.py,sha256=lWl7k2Mp9Axllm0tXzPGJx2zj2zONsyY_p5g424T0Lc,4826
|
@@ -164,7 +164,7 @@ dissect/target/plugins/filesystem/acquire_hash.py,sha256=OVxI19-Bl1tdqCiFMscFMLm
|
|
164
164
|
dissect/target/plugins/filesystem/icat.py,sha256=bOMi04IlljnKwxTWTZJKtK7RxKnabFu3WcXyUwzkE-4,4090
|
165
165
|
dissect/target/plugins/filesystem/resolver.py,sha256=HfyASUFV4F9uD-yFXilFpPTORAsRDvdmTvuYHgOaOWg,4776
|
166
166
|
dissect/target/plugins/filesystem/walkfs.py,sha256=e8HEZcV5Wiua26FGWL3xgiQ_PIhcNvGI5KCdsAx2Nmo,2298
|
167
|
-
dissect/target/plugins/filesystem/yara.py,sha256=
|
167
|
+
dissect/target/plugins/filesystem/yara.py,sha256=JdWqbqDBhKrht3fTroqX7NpBU9khEQUWyMcDgLv2l2g,6686
|
168
168
|
dissect/target/plugins/filesystem/ntfs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
169
169
|
dissect/target/plugins/filesystem/ntfs/mft.py,sha256=AD3w2FIjDAf8x2KEbBhz2NeOA_lxIAmw353w6J3ObYU,9565
|
170
170
|
dissect/target/plugins/filesystem/ntfs/mft_timeline.py,sha256=vvNFAZbr7s3X2OTYf4ES_L6-XsouTXcTymfxnHfZ1Rw,6791
|
@@ -212,7 +212,7 @@ dissect/target/plugins/os/unix/esxi/_os.py,sha256=JOJ6j57vFCojgBNkju-7MG2nQqwl4Q
|
|
212
212
|
dissect/target/plugins/os/unix/etc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
213
213
|
dissect/target/plugins/os/unix/etc/etc.py,sha256=WNCtO7NWOKRDBiV-XjXqgPuGRDE_Zyw6XWz3kTm__QE,2493
|
214
214
|
dissect/target/plugins/os/unix/linux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
215
|
-
dissect/target/plugins/os/unix/linux/_os.py,sha256=
|
215
|
+
dissect/target/plugins/os/unix/linux/_os.py,sha256=n6VkfGYIdZUxcK2C1aPDUY_ZZQEIl0GkrpvIKeguv5o,2812
|
216
216
|
dissect/target/plugins/os/unix/linux/cmdline.py,sha256=AyMfndt3UsmJtoOyZYC8nWq2GZg9oPvn8SiI3M4NxnE,1622
|
217
217
|
dissect/target/plugins/os/unix/linux/environ.py,sha256=UOQD7Xmu754u2oAh3L5g5snuz-gv4jbWbVy46qszYjo,1881
|
218
218
|
dissect/target/plugins/os/unix/linux/iptables.py,sha256=qTzY5PHHXA33WnPYb5NESgoSwI7ECZ8YPoEe_Fmln-8,6045
|
@@ -333,6 +333,7 @@ dissect/target/tools/query.py,sha256=ONHu2FVomLccikb84qBrlhNmEfRoHYFQMcahk_y2c9A
|
|
333
333
|
dissect/target/tools/reg.py,sha256=FDsiBBDxjWVUBTRj8xn82vZe-J_d9piM-TKS3PHZCcM,3193
|
334
334
|
dissect/target/tools/shell.py,sha256=_widEuIRqZhYzcFR52NYI8O2aPFm6tG5Uiv-AIrC32U,45155
|
335
335
|
dissect/target/tools/utils.py,sha256=sQizexY3ui5vmWw4KOBLg5ecK3TPFjD-uxDqRn56ZTY,11304
|
336
|
+
dissect/target/tools/yara.py,sha256=xIom_n78oBiDg6VEBMVk8qmvhYMOPzY5yv9Vl1rDbB4,1754
|
336
337
|
dissect/target/tools/dump/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
337
338
|
dissect/target/tools/dump/run.py,sha256=aD84peRS4zHqC78fH7Vd4ni3m1ZmVP70LyMwBRvoDGY,9463
|
338
339
|
dissect/target/tools/dump/state.py,sha256=YYgCff0kZZ-tx27lJlc9LQ7AfoGnLK5Gyi796OnktA8,9205
|
@@ -345,10 +346,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
|
|
345
346
|
dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
|
346
347
|
dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
|
347
348
|
dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
|
348
|
-
dissect.target-3.19.
|
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.
|
349
|
+
dissect.target-3.19.dev23.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
350
|
+
dissect.target-3.19.dev23.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
351
|
+
dissect.target-3.19.dev23.dist-info/METADATA,sha256=c2q_-Jvv4xRoYAE0jWyTGNV-oOKAD73yjU9Rk5-mavY,12719
|
352
|
+
dissect.target-3.19.dev23.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
353
|
+
dissect.target-3.19.dev23.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
|
354
|
+
dissect.target-3.19.dev23.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
355
|
+
dissect.target-3.19.dev23.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|