dissect.target 3.17.dev26__py3-none-any.whl → 3.17.dev28__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 +66 -49
- dissect/target/loaders/mqtt.py +41 -16
- dissect/target/plugins/os/unix/log/messages.py +53 -8
- dissect/target/tools/query.py +1 -2
- {dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/METADATA +1 -1
- {dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/RECORD +11 -11
- {dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/LICENSE +0 -0
- {dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/WHEEL +0 -0
- {dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/top_level.txt +0 -0
@@ -5,6 +5,7 @@ import re
|
|
5
5
|
from collections import defaultdict
|
6
6
|
from configparser import ConfigParser, MissingSectionHeaderError
|
7
7
|
from io import StringIO
|
8
|
+
from itertools import chain
|
8
9
|
from re import compile, sub
|
9
10
|
from typing import Any, Callable, Iterable, Match, Optional
|
10
11
|
|
@@ -299,7 +300,8 @@ class Parser:
|
|
299
300
|
return
|
300
301
|
|
301
302
|
if section:
|
302
|
-
|
303
|
+
# account for values of sections which are None
|
304
|
+
config = config.get(section, {}) or {}
|
303
305
|
|
304
306
|
for key, value in config.items():
|
305
307
|
if key == option:
|
@@ -508,7 +510,7 @@ class LinuxNetworkManager:
|
|
508
510
|
|
509
511
|
|
510
512
|
def parse_unix_dhcp_log_messages(target) -> list[str]:
|
511
|
-
"""Parse local syslog and cloud init
|
513
|
+
"""Parse local syslog, journal and cloud init-log files for DHCP lease IPs.
|
512
514
|
|
513
515
|
Args:
|
514
516
|
target: Target to discover and obtain network information from.
|
@@ -516,53 +518,68 @@ def parse_unix_dhcp_log_messages(target) -> list[str]:
|
|
516
518
|
Returns:
|
517
519
|
List of DHCP ip addresses.
|
518
520
|
"""
|
519
|
-
ips =
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
521
|
+
ips = set()
|
522
|
+
messages = set()
|
523
|
+
|
524
|
+
for log_func in ["messages", "journal"]:
|
525
|
+
try:
|
526
|
+
messages = chain(messages, getattr(target, log_func)())
|
527
|
+
except PluginError:
|
528
|
+
target.log.debug(f"Could not search for DHCP leases in {log_func} files.")
|
529
|
+
|
530
|
+
if not messages:
|
531
|
+
target.log.warning(f"Could not search for DHCP leases using {log_func}: No log entries found.")
|
532
|
+
|
533
|
+
for record in messages:
|
534
|
+
line = record.message
|
535
|
+
|
536
|
+
# Ubuntu cloud-init
|
537
|
+
if "Received dhcp lease on" in line:
|
538
|
+
interface, ip, netmask = re.search(r"Received dhcp lease on (\w{0,}) for (\S+)\/(\S+)", line).groups()
|
539
|
+
ips.add(ip)
|
540
|
+
continue
|
541
|
+
|
542
|
+
# Ubuntu DHCP
|
543
|
+
if ("DHCPv4" in line or "DHCPv6" in line) and " address " in line and " via " in line:
|
544
|
+
ip = line.split(" address ")[1].split(" via ")[0].strip().split("/")[0]
|
545
|
+
ips.add(ip)
|
546
|
+
continue
|
547
|
+
|
548
|
+
# Ubuntu DHCP NetworkManager
|
549
|
+
if "option ip_address" in line and ("dhcp4" in line or "dhcp6" in line) and "=> '" in line:
|
550
|
+
ip = line.split("=> '")[1].replace("'", "").strip()
|
551
|
+
ips.add(ip)
|
552
|
+
continue
|
553
|
+
|
554
|
+
# Debian and CentOS dhclient
|
555
|
+
if hasattr(record, "daemon") and record.daemon == "dhclient" and "bound to" in line:
|
556
|
+
ip = line.split("bound to")[1].split(" ")[1].strip()
|
557
|
+
ips.add(ip)
|
558
|
+
continue
|
559
|
+
|
560
|
+
# CentOS DHCP and general NetworkManager
|
561
|
+
if " address " in line and ("dhcp4" in line or "dhcp6" in line):
|
562
|
+
ip = line.split(" address ")[1].strip()
|
563
|
+
ips.add(ip)
|
564
|
+
continue
|
565
|
+
|
566
|
+
# Ubuntu/Debian DHCP networkd (Journal)
|
567
|
+
if (
|
568
|
+
hasattr(record, "code_func")
|
569
|
+
and record.code_func == "dhcp_lease_acquired"
|
570
|
+
and " address " in line
|
571
|
+
and " via " in line
|
572
|
+
):
|
573
|
+
interface, ip, netmask, gateway = re.search(
|
574
|
+
r"^(\S+): DHCPv[4|6] address (\S+)\/(\S+) via (\S+)", line
|
575
|
+
).groups()
|
576
|
+
ips.add(ip)
|
577
|
+
continue
|
578
|
+
|
579
|
+
# Journals and syslogs can be large and slow to iterate,
|
580
|
+
# so we stop if we have some results and have reached the journal plugin.
|
581
|
+
if len(ips) >= 2 and record._desc.name == "linux/log/journal":
|
582
|
+
break
|
566
583
|
|
567
584
|
return ips
|
568
585
|
|
dissect/target/loaders/mqtt.py
CHANGED
@@ -65,6 +65,9 @@ class MQTTStream(AlignedStream):
|
|
65
65
|
class MQTTConnection:
|
66
66
|
broker = None
|
67
67
|
host = None
|
68
|
+
prev = -1
|
69
|
+
factor = 1
|
70
|
+
prefetch_factor_inc = 10
|
68
71
|
|
69
72
|
def __init__(self, broker: Broker, host: str):
|
70
73
|
self.broker = broker
|
@@ -95,20 +98,32 @@ class MQTTConnection:
|
|
95
98
|
|
96
99
|
def read(self, disk_id: int, offset: int, length: int, optimization_strategy: int) -> bytes:
|
97
100
|
message = None
|
98
|
-
self.broker.seek(self.host, disk_id, offset, length, optimization_strategy)
|
99
101
|
|
102
|
+
message = self.broker.read(self.host, disk_id, offset, length)
|
103
|
+
if message:
|
104
|
+
return message.data
|
105
|
+
|
106
|
+
if self.prev == offset - (length * self.factor):
|
107
|
+
if self.factor < 500:
|
108
|
+
self.factor += self.prefetch_factor_inc
|
109
|
+
else:
|
110
|
+
self.factor = 1
|
111
|
+
|
112
|
+
self.prev = offset
|
113
|
+
flength = length * self.factor
|
114
|
+
self.broker.factor = self.factor
|
115
|
+
self.broker.seek(self.host, disk_id, offset, flength, optimization_strategy)
|
100
116
|
attempts = 0
|
101
117
|
while True:
|
102
|
-
message
|
103
|
-
|
104
|
-
if message:
|
118
|
+
if message := self.broker.read(self.host, disk_id, offset, length):
|
119
|
+
# don't waste time with sleep if we have a response
|
105
120
|
break
|
106
121
|
|
107
122
|
attempts += 1
|
108
|
-
time.sleep(0.
|
109
|
-
if attempts >
|
123
|
+
time.sleep(0.1)
|
124
|
+
if attempts > 300:
|
110
125
|
# message might have not reached agent, resend...
|
111
|
-
self.broker.seek(self.host, disk_id, offset,
|
126
|
+
self.broker.seek(self.host, disk_id, offset, flength, optimization_strategy)
|
112
127
|
attempts = 0
|
113
128
|
|
114
129
|
return message.data
|
@@ -127,6 +142,7 @@ class Broker:
|
|
127
142
|
diskinfo = {}
|
128
143
|
index = {}
|
129
144
|
topo = {}
|
145
|
+
factor = 1
|
130
146
|
|
131
147
|
def __init__(self, broker: Broker, port: str, key: str, crt: str, ca: str, case: str, **kwargs):
|
132
148
|
self.broker_host = broker
|
@@ -137,10 +153,13 @@ class Broker:
|
|
137
153
|
self.case = case
|
138
154
|
self.command = kwargs.get("command", None)
|
139
155
|
|
156
|
+
def clear_cache(self) -> None:
|
157
|
+
self.index = {}
|
158
|
+
|
140
159
|
@suppress
|
141
160
|
def read(self, host: str, disk_id: int, seek_address: int, read_length: int) -> SeekMessage:
|
142
161
|
key = f"{host}-{disk_id}-{seek_address}-{read_length}"
|
143
|
-
return self.index.
|
162
|
+
return self.index.get(key)
|
144
163
|
|
145
164
|
@suppress
|
146
165
|
def disk(self, host: str) -> DiskMessage:
|
@@ -165,14 +184,15 @@ class Broker:
|
|
165
184
|
disk_id = tokens[3]
|
166
185
|
seek_address = int(tokens[4], 16)
|
167
186
|
read_length = int(tokens[5], 16)
|
168
|
-
msg = SeekMessage(data=payload)
|
169
187
|
|
170
|
-
|
188
|
+
for i in range(self.factor):
|
189
|
+
sublength = int(read_length / self.factor)
|
190
|
+
start = i * sublength
|
191
|
+
key = f"{hostname}-{disk_id}-{seek_address+start}-{sublength}"
|
192
|
+
if key in self.index:
|
193
|
+
continue
|
171
194
|
|
172
|
-
|
173
|
-
return
|
174
|
-
|
175
|
-
self.index[key] = msg
|
195
|
+
self.index[key] = SeekMessage(data=payload[start : start + sublength])
|
176
196
|
|
177
197
|
def _on_id(self, hostname: str, payload: bytes) -> None:
|
178
198
|
key = hostname
|
@@ -204,9 +224,14 @@ class Broker:
|
|
204
224
|
elif response == "ID":
|
205
225
|
self._on_id(hostname, msg.payload)
|
206
226
|
|
207
|
-
def seek(self, host: str, disk_id: int, offset: int,
|
227
|
+
def seek(self, host: str, disk_id: int, offset: int, flength: int, optimization_strategy: int) -> None:
|
228
|
+
length = int(flength / self.factor)
|
229
|
+
key = f"{host}-{disk_id}-{offset}-{length}"
|
230
|
+
if key in self.index:
|
231
|
+
return
|
232
|
+
|
208
233
|
self.mqtt_client.publish(
|
209
|
-
f"{self.case}/{host}/SEEK/{disk_id}/{hex(offset)}/{hex(
|
234
|
+
f"{self.case}/{host}/SEEK/{disk_id}/{hex(offset)}/{hex(flength)}", pack("<I", optimization_strategy)
|
210
235
|
)
|
211
236
|
|
212
237
|
def info(self, host: str) -> None:
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import re
|
2
|
-
from
|
2
|
+
from pathlib import Path
|
3
3
|
from typing import Iterator
|
4
4
|
|
5
|
+
from dissect.target import Target
|
5
6
|
from dissect.target.exceptions import UnsupportedPluginError
|
6
7
|
from dissect.target.helpers.record import TargetRecordDescriptor
|
7
8
|
from dissect.target.helpers.utils import year_rollover_helper
|
@@ -23,17 +24,28 @@ RE_TS = re.compile(r"(\w+\s{1,2}\d+\s\d{2}:\d{2}:\d{2})")
|
|
23
24
|
RE_DAEMON = re.compile(r"^[^:]+:\d+:\d+[^\[\]:]+\s([^\[:]+)[\[|:]{1}")
|
24
25
|
RE_PID = re.compile(r"\w\[(\d+)\]")
|
25
26
|
RE_MSG = re.compile(r"[^:]+:\d+:\d+[^:]+:\s(.*)$")
|
27
|
+
RE_CLOUD_INIT_LINE = re.compile(r"(?P<ts>.*) - (?P<daemon>.*)\[(?P<log_level>\w+)\]\: (?P<message>.*)$")
|
26
28
|
|
27
29
|
|
28
30
|
class MessagesPlugin(Plugin):
|
31
|
+
def __init__(self, target: Target):
|
32
|
+
super().__init__(target)
|
33
|
+
self.log_files = set(self._find_log_files())
|
34
|
+
|
35
|
+
def _find_log_files(self) -> Iterator[Path]:
|
36
|
+
log_dirs = ["/var/log/", "/var/log/installer/"]
|
37
|
+
file_globs = ["syslog*", "messages*", "cloud-init.log*"]
|
38
|
+
for log_dir in log_dirs:
|
39
|
+
for glob in file_globs:
|
40
|
+
yield from self.target.fs.path(log_dir).glob(glob)
|
41
|
+
|
29
42
|
def check_compatible(self) -> None:
|
30
|
-
|
31
|
-
|
32
|
-
raise UnsupportedPluginError("No message files found")
|
43
|
+
if not self.log_files:
|
44
|
+
raise UnsupportedPluginError("No log files found")
|
33
45
|
|
34
46
|
@export(record=MessagesRecord)
|
35
47
|
def syslog(self) -> Iterator[MessagesRecord]:
|
36
|
-
"""Return contents of /var/log/messages
|
48
|
+
"""Return contents of /var/log/messages*, /var/log/syslog* and cloud-init logs.
|
37
49
|
|
38
50
|
See ``messages`` for more information.
|
39
51
|
"""
|
@@ -41,7 +53,7 @@ class MessagesPlugin(Plugin):
|
|
41
53
|
|
42
54
|
@export(record=MessagesRecord)
|
43
55
|
def messages(self) -> Iterator[MessagesRecord]:
|
44
|
-
"""Return contents of /var/log/messages
|
56
|
+
"""Return contents of /var/log/messages*, /var/log/syslog* and cloud-init logs.
|
45
57
|
|
46
58
|
Note: due to year rollover detection, the contents of the files are returned in reverse.
|
47
59
|
|
@@ -52,12 +64,16 @@ class MessagesPlugin(Plugin):
|
|
52
64
|
References:
|
53
65
|
- https://geek-university.com/linux/var-log-messages-file/
|
54
66
|
- https://www.geeksforgeeks.org/file-timestamps-mtime-ctime-and-atime-in-linux/
|
67
|
+
- https://cloudinit.readthedocs.io/en/latest/development/logging.html#logging-command-output
|
55
68
|
"""
|
56
69
|
|
57
70
|
tzinfo = self.target.datetime.tzinfo
|
58
71
|
|
59
|
-
|
60
|
-
|
72
|
+
for log_file in self.log_files:
|
73
|
+
if "cloud-init" in log_file.name:
|
74
|
+
yield from self._parse_cloud_init_log(log_file)
|
75
|
+
continue
|
76
|
+
|
61
77
|
for ts, line in year_rollover_helper(log_file, RE_TS, DEFAULT_TS_LOG_FORMAT, tzinfo):
|
62
78
|
daemon = dict(enumerate(RE_DAEMON.findall(line))).get(0)
|
63
79
|
pid = dict(enumerate(RE_PID.findall(line))).get(0)
|
@@ -71,3 +87,32 @@ class MessagesPlugin(Plugin):
|
|
71
87
|
source=log_file,
|
72
88
|
_target=self.target,
|
73
89
|
)
|
90
|
+
|
91
|
+
def _parse_cloud_init_log(self, log_file: Path) -> Iterator[MessagesRecord]:
|
92
|
+
"""Parse a cloud-init.log file.
|
93
|
+
|
94
|
+
Lines are structured in the following format:
|
95
|
+
``YYYY-MM-DD HH:MM:SS,000 - dhcp.py[DEBUG]: Received dhcp lease on IFACE for IP/MASK``
|
96
|
+
|
97
|
+
NOTE: ``cloud-init-output.log`` files are not supported as they do not contain structured logs.
|
98
|
+
|
99
|
+
Args:
|
100
|
+
``log_file``: path to cloud-init.log file.
|
101
|
+
|
102
|
+
Returns: ``MessagesRecord``
|
103
|
+
"""
|
104
|
+
for line in log_file.open("rt").readlines():
|
105
|
+
if line := line.strip():
|
106
|
+
if match := RE_CLOUD_INIT_LINE.match(line):
|
107
|
+
match = match.groupdict()
|
108
|
+
yield MessagesRecord(
|
109
|
+
ts=match["ts"].split(",")[0],
|
110
|
+
daemon=match["daemon"],
|
111
|
+
pid=None,
|
112
|
+
message=match["message"],
|
113
|
+
source=log_file,
|
114
|
+
_target=self.target,
|
115
|
+
)
|
116
|
+
else:
|
117
|
+
self.target.log.warning("Could not match cloud-init log line")
|
118
|
+
self.target.log.debug("No match for line '%s'", line)
|
dissect/target/tools/query.py
CHANGED
@@ -173,8 +173,7 @@ def main():
|
|
173
173
|
collected_plugins = {}
|
174
174
|
|
175
175
|
if targets:
|
176
|
-
for
|
177
|
-
plugin_target = Target.open(target)
|
176
|
+
for plugin_target in Target.open_all(targets, args.children):
|
178
177
|
if isinstance(plugin_target._loader, ProxyLoader):
|
179
178
|
parser.error("can't list compatible plugins for remote targets.")
|
180
179
|
funcs, _ = find_plugin_functions(plugin_target, args.list, compatibility=True, show_hidden=True)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.17.
|
3
|
+
Version: 3.17.dev28
|
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
|
@@ -57,7 +57,7 @@ dissect/target/helpers/loaderutil.py,sha256=kiyMWra_gVxfNSGwLlgxLcuuqAYuCMDc5NiC
|
|
57
57
|
dissect/target/helpers/localeutil.py,sha256=Y4Fh4jDSGfm5356xSLMriUCN8SZP_FAHg_iodkAxNq4,1504
|
58
58
|
dissect/target/helpers/mount.py,sha256=JxhUYyEbDnHfzPpfuWy4nV9OwCJPoDSGdHHNiyvd_l0,3949
|
59
59
|
dissect/target/helpers/mui.py,sha256=i-7XoHbu4WO2fYapK9yGAMW04rFlgRispknc1KQIS5Q,22258
|
60
|
-
dissect/target/helpers/network_managers.py,sha256=
|
60
|
+
dissect/target/helpers/network_managers.py,sha256=uRh_P8ICbKke2N7eFJ6AS2-I5DmIRiaQUlxR7oqxPaU,24975
|
61
61
|
dissect/target/helpers/polypath.py,sha256=h8p7m_OCNiQljGwoZh5Aflr9H2ot6CZr6WKq1OSw58o,2175
|
62
62
|
dissect/target/helpers/protobuf.py,sha256=NwKrZD4q9v7J8GnZX9gbzMUMV5pR78eAV17jgWOz_EY,1730
|
63
63
|
dissect/target/helpers/record.py,sha256=lWl7k2Mp9Axllm0tXzPGJx2zj2zONsyY_p5g424T0Lc,4826
|
@@ -85,7 +85,7 @@ dissect/target/loaders/itunes.py,sha256=69aMTQiiGYpmD_EYSmf9mO1re8C3jAZIEStmwlMx
|
|
85
85
|
dissect/target/loaders/kape.py,sha256=t5TfrGLqPeIpUUpXzIl6aHsqXMEGDqJ5YwDCs07DiBA,1237
|
86
86
|
dissect/target/loaders/local.py,sha256=Ul-LCd_fY7SyWOVR6nH-NqbkuNpxoZVmffwrkvQElU8,16453
|
87
87
|
dissect/target/loaders/log.py,sha256=cCkDIRS4aPlX3U-n_jUKaI2FPSV3BDpfqKceaU7rBbo,1507
|
88
|
-
dissect/target/loaders/mqtt.py,sha256=
|
88
|
+
dissect/target/loaders/mqtt.py,sha256=D8AmdOz2atD92z8bhjVFi3tC1H7pYmP4UrOCtMgfwMY,10396
|
89
89
|
dissect/target/loaders/multiraw.py,sha256=4a3ZST0NwjnfPDxHkcEfAcX2ddUlT_C-rcrMHNg1wp4,1046
|
90
90
|
dissect/target/loaders/ova.py,sha256=6h4O-7i87J394C6KgLsPkdXRAKNwtPubzLNS3vBGs7U,744
|
91
91
|
dissect/target/loaders/ovf.py,sha256=ELMq6J2y6cPKbp7pjWAqMMnFYefWxXNqzIiAQdvGGXQ,1061
|
@@ -247,7 +247,7 @@ dissect/target/plugins/os/unix/log/audit.py,sha256=OjorWTmCFvCI5RJq6m6WNW0Lhb-po
|
|
247
247
|
dissect/target/plugins/os/unix/log/auth.py,sha256=l7gCuRdvv9gL0U1N0yrR9hVsMnr4t_k4t-n-f6PrOxg,2388
|
248
248
|
dissect/target/plugins/os/unix/log/journal.py,sha256=eiNNVLmKWFj4dTQX8PNRNgKpVwzQWEHEsKyYfGUAPXQ,17376
|
249
249
|
dissect/target/plugins/os/unix/log/lastlog.py,sha256=eL_dbB1sPoy0tyavIjT457ZLVfXcCr17GiwDrMEEh8A,2458
|
250
|
-
dissect/target/plugins/os/unix/log/messages.py,sha256=
|
250
|
+
dissect/target/plugins/os/unix/log/messages.py,sha256=CXA-SkMPLaCgnTQg9nzII-7tO8Il_ENQmuYvDxo33rI,4698
|
251
251
|
dissect/target/plugins/os/unix/log/utmp.py,sha256=21tvzG977LqzRShV6uAoU-83WDcLUrI_Tv__2ZVi9rw,7756
|
252
252
|
dissect/target/plugins/os/windows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
253
253
|
dissect/target/plugins/os/windows/_os.py,sha256=EA9B9Rgb1C9NMvlX3gXhTRFXYaI6zrrKRg0OYq4v1ts,12589
|
@@ -320,7 +320,7 @@ dissect/target/tools/fs.py,sha256=cizCrW8rqdpT1irA8g6mslkaXX7CynWVQ7fvRUrcxNU,37
|
|
320
320
|
dissect/target/tools/info.py,sha256=3smHr8I71yj3kCjsQ5nXkOHI9T_N8UwvkVa1CNOxB-s,5461
|
321
321
|
dissect/target/tools/logging.py,sha256=5ZnumtMWLyslxfrUGZ4ntRyf3obOOhmn8SBjKfdLcEg,4174
|
322
322
|
dissect/target/tools/mount.py,sha256=L_0tSmiBdW4aSaF0vXjB0bAkTC0kmT2N1hrbW6s5Jow,3254
|
323
|
-
dissect/target/tools/query.py,sha256=
|
323
|
+
dissect/target/tools/query.py,sha256=ONHu2FVomLccikb84qBrlhNmEfRoHYFQMcahk_y2c9A,15580
|
324
324
|
dissect/target/tools/reg.py,sha256=FDsiBBDxjWVUBTRj8xn82vZe-J_d9piM-TKS3PHZCcM,3193
|
325
325
|
dissect/target/tools/shell.py,sha256=4v6Z06YJDjKv6e6SRvWNjQ2n_KHo_CjL4P0w1_gY_ro,44827
|
326
326
|
dissect/target/tools/utils.py,sha256=sQizexY3ui5vmWw4KOBLg5ecK3TPFjD-uxDqRn56ZTY,11304
|
@@ -336,10 +336,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
|
|
336
336
|
dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
|
337
337
|
dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
|
338
338
|
dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
|
339
|
-
dissect.target-3.17.
|
340
|
-
dissect.target-3.17.
|
341
|
-
dissect.target-3.17.
|
342
|
-
dissect.target-3.17.
|
343
|
-
dissect.target-3.17.
|
344
|
-
dissect.target-3.17.
|
345
|
-
dissect.target-3.17.
|
339
|
+
dissect.target-3.17.dev28.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
340
|
+
dissect.target-3.17.dev28.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
341
|
+
dissect.target-3.17.dev28.dist-info/METADATA,sha256=BUIYxmU-67ACgU91l-B3EP-B6QpBkjk-OBY7EOMDfBU,11300
|
342
|
+
dissect.target-3.17.dev28.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
343
|
+
dissect.target-3.17.dev28.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
|
344
|
+
dissect.target-3.17.dev28.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
345
|
+
dissect.target-3.17.dev28.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.17.dev26.dist-info → dissect.target-3.17.dev28.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|