dissect.target 3.15.dev13__py3-none-any.whl → 3.15.dev14__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,59 +5,15 @@ from typing import Iterator
5
5
 
6
6
  from dissect.target import Target
7
7
  from dissect.target.exceptions import UnsupportedPluginError
8
- from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
9
8
  from dissect.target.helpers.fsutil import TargetPath
10
- from dissect.target.helpers.record import create_extended_descriptor
11
9
  from dissect.target.helpers.ssh import SSHPrivateKey
12
- from dissect.target.plugin import Plugin, export
13
-
14
- OpenSSHUserRecordDescriptor = create_extended_descriptor([UserRecordDescriptorExtension])
15
-
16
- COMMON_ELLEMENTS = [
17
- ("string", "key_type"),
18
- ("string", "comment"),
19
- ("path", "path"),
20
- ]
21
-
22
- AuthorizedKeysRecord = OpenSSHUserRecordDescriptor(
23
- "application/openssh/authorized_keys",
24
- [
25
- *COMMON_ELLEMENTS,
26
- ("string", "public_key"),
27
- ("string", "options"),
28
- ],
29
- )
30
-
31
-
32
- KnownHostRecord = OpenSSHUserRecordDescriptor(
33
- "application/openssh/known_host",
34
- [
35
- *COMMON_ELLEMENTS,
36
- ("string", "hostname_pattern"),
37
- ("string", "public_key"),
38
- ("string", "marker"),
39
- ],
40
- )
41
-
42
-
43
- PrivateKeyRecord = OpenSSHUserRecordDescriptor(
44
- "application/openssh/private_key",
45
- [
46
- *COMMON_ELLEMENTS,
47
- ("datetime", "mtime_ts"),
48
- ("string", "key_format"),
49
- ("string", "public_key"),
50
- ("boolean", "encrypted"),
51
- ],
52
- )
53
-
54
- PublicKeyRecord = OpenSSHUserRecordDescriptor(
55
- "application/openssh/public_key",
56
- [
57
- *COMMON_ELLEMENTS,
58
- ("datetime", "mtime_ts"),
59
- ("string", "public_key"),
60
- ],
10
+ from dissect.target.plugin import export
11
+ from dissect.target.plugins.apps.ssh.ssh import (
12
+ AuthorizedKeysRecord,
13
+ KnownHostRecord,
14
+ PrivateKeyRecord,
15
+ PublicKeyRecord,
16
+ SSHPlugin,
61
17
  )
62
18
 
63
19
 
@@ -72,8 +28,8 @@ def find_sshd_directory(target: Target) -> TargetPath:
72
28
  return target.fs.path("/etc/ssh/")
73
29
 
74
30
 
75
- class OpenSSHPlugin(Plugin):
76
- __namespace__ = "ssh"
31
+ class OpenSSHPlugin(SSHPlugin):
32
+ __namespace__ = "openssh"
77
33
 
78
34
  SSHD_DIRECTORIES = ["/sysvol/ProgramData/ssh", "/etc/ssh"]
79
35
 
@@ -136,7 +92,8 @@ class OpenSSHPlugin(Plugin):
136
92
 
137
93
  for hostname in hostnames:
138
94
  yield KnownHostRecord(
139
- hostname_pattern=hostname,
95
+ host=hostname,
96
+ port=None,
140
97
  key_type=keytype,
141
98
  public_key=public_key,
142
99
  comment=comment,
@@ -3,8 +3,9 @@ from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, Union
3
3
  from dissect.target import Target
4
4
  from dissect.target.exceptions import UnsupportedPluginError
5
5
  from dissect.target.helpers.record import DynamicDescriptor, TargetRecordDescriptor
6
- from dissect.target.plugin import Plugin, export
6
+ from dissect.target.plugin import export
7
7
  from dissect.target.plugins.apps.ssh.openssh import find_sshd_directory
8
+ from dissect.target.plugins.apps.ssh.ssh import SSHPlugin
8
9
 
9
10
  if TYPE_CHECKING:
10
11
  from dissect.target.plugins.general.config import ConfigurationTreePlugin
@@ -72,8 +73,8 @@ SSHD_MULTIPLE_DEFINITIONS_ALLOWED_FIELDS = (
72
73
  )
73
74
 
74
75
 
75
- class SSHServerPlugin(Plugin):
76
- __namespace__ = "sshd"
76
+ class SSHServerPlugin(SSHPlugin):
77
+ __namespace__ = "opensshd"
77
78
 
78
79
  def __init__(self, target: Target):
79
80
  super().__init__(target)
@@ -0,0 +1,236 @@
1
+ import logging
2
+ from datetime import datetime
3
+ from pathlib import Path
4
+ from typing import Iterator, Optional, Union
5
+
6
+ from Crypto.PublicKey import ECC, RSA
7
+ from flow.record.fieldtypes import posix_path, windows_path
8
+
9
+ from dissect.target.exceptions import RegistryKeyNotFoundError, UnsupportedPluginError
10
+ from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
11
+ from dissect.target.helpers.fsutil import TargetPath, open_decompress
12
+ from dissect.target.helpers.record import create_extended_descriptor
13
+ from dissect.target.helpers.regutil import RegistryKey
14
+ from dissect.target.plugin import export
15
+ from dissect.target.plugins.apps.ssh.ssh import KnownHostRecord, SSHPlugin
16
+ from dissect.target.plugins.general.users import UserDetails
17
+
18
+ log = logging.getLogger(__name__)
19
+
20
+ PuTTYUserRecordDescriptor = create_extended_descriptor([UserRecordDescriptorExtension])
21
+ PuTTYSessionRecord = PuTTYUserRecordDescriptor(
22
+ "application/putty/saved_session",
23
+ [
24
+ ("datetime", "ts"),
25
+ ("string", "session_name"),
26
+ ("string", "protocol"),
27
+ ("string", "host"),
28
+ ("string", "user"),
29
+ ("varint", "port"),
30
+ ("string", "remote_command"),
31
+ ("string", "port_forward"),
32
+ ("string", "manual_ssh_host_keys"),
33
+ ("path", "path"),
34
+ ],
35
+ )
36
+
37
+
38
+ class PuTTYPlugin(SSHPlugin):
39
+ """Extract artifacts from the PuTTY client.
40
+
41
+ NOTE:
42
+ - Does not parse ``$HOME/.putty/randomseed`` (GNU/Linux)
43
+ and ``HKCU\\Software\\SimonTatham\\PuTTY\\RandSeedFile`` (Windows)
44
+
45
+ Resources:
46
+ - http://www.chiark.greenend.org.uk/~sgtatham/putty/0.78/puttydoc.txt
47
+ - http://www.chiark.greenend.org.uk/~sgtatham/putty/faq.html#faq-settings
48
+ """
49
+
50
+ __namespace__ = "putty"
51
+
52
+ def __init__(self, target):
53
+ super().__init__(target)
54
+
55
+ self.regf_installs, self.path_installs = self._detect_putty()
56
+
57
+ def _detect_putty(
58
+ self,
59
+ ) -> tuple[list[set[RegistryKey, Optional[UserDetails]]], list[set[TargetPath, Optional[UserDetails]]]]:
60
+ regf_installs, path_installs = [], []
61
+
62
+ if self.target.has_function("registry"):
63
+ for key in self.target.registry.keys("HKCU\\Software\\SimonTatham\\PuTTY"):
64
+ user_details = self.target.registry.get_user_details(key)
65
+ regf_installs.append((key, user_details))
66
+
67
+ for user_details in self.target.user_details.all_with_home():
68
+ if (putty_path := user_details.home_path.joinpath(".putty")).exists():
69
+ path_installs.append((putty_path, user_details))
70
+
71
+ return regf_installs, path_installs
72
+
73
+ def check_compatible(self) -> None:
74
+ if not any(self.regf_installs + self.path_installs):
75
+ raise UnsupportedPluginError("No PuTTY installations found")
76
+
77
+ @export(record=KnownHostRecord)
78
+ def known_hosts(self) -> Iterator[KnownHostRecord]:
79
+ """Parse PuTTY saved SshHostKeys."""
80
+
81
+ for putty_key, user_details in self.regf_installs:
82
+ yield from self._regf_known_hosts(putty_key, user_details)
83
+
84
+ for putty_path, user_details in self.path_installs:
85
+ yield from self._path_known_hosts(putty_path, user_details)
86
+
87
+ def _regf_known_hosts(self, putty_key: RegistryKey, user_details: UserDetails) -> Iterator[KnownHostRecord]:
88
+ """Parse PuTTY traces in Windows registry."""
89
+
90
+ try:
91
+ ssh_host_keys = putty_key.subkey("SshHostKeys")
92
+ except RegistryKeyNotFoundError:
93
+ return
94
+
95
+ for entry in ssh_host_keys.values():
96
+ key_type, host = entry.name.split("@")
97
+ port, host = host.split(":")
98
+
99
+ yield KnownHostRecord(
100
+ mtime_ts=ssh_host_keys.ts,
101
+ host=host,
102
+ port=port,
103
+ key_type=key_type,
104
+ public_key=construct_public_key(key_type, entry.value),
105
+ comment="",
106
+ marker=None,
107
+ path=windows_path(ssh_host_keys.path),
108
+ _target=self.target,
109
+ _user=user_details.user if user_details else None,
110
+ )
111
+
112
+ def _path_known_hosts(self, putty_path: TargetPath, user_details: UserDetails) -> Iterator[KnownHostRecord]:
113
+ """Parse PuTTY traces in ``.putty`` folders"""
114
+ ssh_host_keys_path = putty_path.joinpath("sshhostkeys")
115
+
116
+ if ssh_host_keys_path.exists():
117
+ ts = ssh_host_keys_path.stat().st_mtime
118
+
119
+ for line in open_decompress(ssh_host_keys_path, "rt"):
120
+ parts = line.split()
121
+ key_type, host = parts[0].split("@")
122
+ port, host = host.split(":")
123
+
124
+ yield KnownHostRecord(
125
+ mtime_ts=ts,
126
+ host=host,
127
+ port=port,
128
+ key_type=key_type,
129
+ public_key=construct_public_key(key_type, parts[1]),
130
+ comment="",
131
+ marker=None,
132
+ path=posix_path(ssh_host_keys_path),
133
+ _target=self.target,
134
+ _user=user_details.user if user_details else None,
135
+ )
136
+
137
+ @export(record=PuTTYSessionRecord)
138
+ def sessions(self) -> Iterator[PuTTYSessionRecord]:
139
+ """Parse PuTTY saved session configuration files."""
140
+
141
+ for putty_key, user_details in self.regf_installs:
142
+ yield from self._regf_sessions(putty_key, user_details)
143
+
144
+ for putty_path, user_details in self.path_installs:
145
+ yield from self._path_sessions(putty_path, user_details)
146
+
147
+ def _regf_sessions(self, putty_key: RegistryKey, user_details: UserDetails) -> Iterator[PuTTYSessionRecord]:
148
+ try:
149
+ sessions = putty_key.subkey("Sessions")
150
+ except RegistryKeyNotFoundError:
151
+ return
152
+
153
+ for session in sessions.subkeys():
154
+ cfg = {s.name: s.value for s in session.values()}
155
+ yield from self._build_session_record(
156
+ session.ts, session.name, windows_path(session.path), cfg, user_details
157
+ )
158
+
159
+ def _path_sessions(self, putty_path: TargetPath, user_details: UserDetails) -> Iterator[PuTTYSessionRecord]:
160
+ sessions_dir = putty_path.joinpath("sessions")
161
+ if sessions_dir.exists():
162
+ for session in sessions_dir.glob("*"):
163
+ if session.is_file():
164
+ cfg = dict(map(str.strip, line.split("=", maxsplit=1)) for line in session.open("rt").readlines())
165
+ yield from self._build_session_record(
166
+ session.stat().st_mtime, session.name, session, cfg, user_details
167
+ )
168
+
169
+ def _build_session_record(
170
+ self, ts: float, name: Union[float, datetime], source: Path, cfg: dict, user_details: UserDetails
171
+ ) -> PuTTYSessionRecord:
172
+ host, user = parse_host_user(cfg.get("HostName"), cfg.get("UserName"))
173
+
174
+ yield PuTTYSessionRecord(
175
+ ts=ts,
176
+ session_name=name,
177
+ protocol=cfg.get("Protocol"),
178
+ host=host,
179
+ user=user,
180
+ port=cfg.get("PortNumber"),
181
+ remote_command=cfg.get("RemoteCommand"),
182
+ port_forward=cfg.get("PortForwardings"),
183
+ manual_ssh_host_keys=cfg.get("SSHManualHostKeys"),
184
+ path=source,
185
+ _target=self.target,
186
+ _user=user_details.user if user_details else None,
187
+ )
188
+
189
+
190
+ def parse_host_user(host: str, user: str) -> tuple[str, str]:
191
+ """Parse host and user from PuTTY hostname component."""
192
+ if "@" in host:
193
+ parsed_user, parsed_host = host.split("@")
194
+ user = user or parsed_user
195
+ host = parsed_host
196
+
197
+ return host, user
198
+
199
+
200
+ def construct_public_key(key_type: str, iv: str) -> str:
201
+ """Returns OpenSSH format public key calculated from PuTTY SshHostKeys format.
202
+
203
+ PuTTY stores raw public key components instead of OpenSSH-formatted public keys
204
+ or fingerprints. With RSA public keys the exponent and modulus are stored.
205
+ With ECC keys the x and y prime coordinates are stored together with the curve type.
206
+
207
+ Currently supports ``ssh-ed25519``, ``ecdsa-sha2-nistp256`` and ``rsa2`` key types.
208
+
209
+ NOTE:
210
+ - Sha256 fingerprints of the reconstructed public keys are currently not generated.
211
+ - More key types could be supported in the future.
212
+
213
+ Resources:
214
+ - https://github.com/github/putty/blob/master/contrib/kh2reg.py
215
+ - https://pycryptodome.readthedocs.io/en/latest/src/public_key/rsa.html
216
+ - https://pycryptodome.readthedocs.io/en/latest/src/public_key/ecc.html
217
+ - https://github.com/mkorthof/reg2kh
218
+ """
219
+
220
+ if key_type == "ssh-ed25519":
221
+ x, y = iv.split(",")
222
+ key = ECC.construct(curve="ed25519", point_x=int(x, 16), point_y=int(y, 16))
223
+ return key.public_key().export_key(format="OpenSSH").split()[-1]
224
+
225
+ if key_type == "ecdsa-sha2-nistp256":
226
+ _, x, y = iv.split(",")
227
+ key = ECC.construct(curve="NIST P-256", point_x=int(x, 16), point_y=int(y, 16))
228
+ return key.public_key().export_key(format="OpenSSH").split()[-1]
229
+
230
+ if key_type == "rsa2":
231
+ exponent, modulus = iv.split(",")
232
+ key = RSA.construct((int(modulus, 16), int(exponent, 16)))
233
+ return key.public_key().export_key(format="OpenSSH").decode("utf-8").split()[-1]
234
+
235
+ log.warning("Could not reconstruct public key: type %s not implemented.", key_type)
236
+ return iv
@@ -0,0 +1,58 @@
1
+ from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
2
+ from dissect.target.helpers.record import create_extended_descriptor
3
+ from dissect.target.plugin import NamespacePlugin
4
+
5
+ OpenSSHUserRecordDescriptor = create_extended_descriptor([UserRecordDescriptorExtension])
6
+
7
+ COMMON_ELLEMENTS = [
8
+ ("string", "key_type"),
9
+ ("string", "comment"),
10
+ ("path", "path"),
11
+ ]
12
+
13
+ AuthorizedKeysRecord = OpenSSHUserRecordDescriptor(
14
+ "application/openssh/authorized_keys",
15
+ [
16
+ *COMMON_ELLEMENTS,
17
+ ("string", "public_key"),
18
+ ("string", "options"),
19
+ ],
20
+ )
21
+
22
+
23
+ KnownHostRecord = OpenSSHUserRecordDescriptor(
24
+ "application/openssh/known_host",
25
+ [
26
+ ("datetime", "mtime_ts"),
27
+ *COMMON_ELLEMENTS,
28
+ ("string", "host"),
29
+ ("varint", "port"),
30
+ ("string", "public_key"),
31
+ ("string", "marker"),
32
+ ],
33
+ )
34
+
35
+
36
+ PrivateKeyRecord = OpenSSHUserRecordDescriptor(
37
+ "application/openssh/private_key",
38
+ [
39
+ ("datetime", "mtime_ts"),
40
+ *COMMON_ELLEMENTS,
41
+ ("string", "key_format"),
42
+ ("string", "public_key"),
43
+ ("boolean", "encrypted"),
44
+ ],
45
+ )
46
+
47
+ PublicKeyRecord = OpenSSHUserRecordDescriptor(
48
+ "application/openssh/public_key",
49
+ [
50
+ ("datetime", "mtime_ts"),
51
+ *COMMON_ELLEMENTS,
52
+ ("string", "public_key"),
53
+ ],
54
+ )
55
+
56
+
57
+ class SSHPlugin(NamespacePlugin):
58
+ __namespace__ = "ssh"
@@ -329,7 +329,7 @@ class RegistryPlugin(Plugin):
329
329
  @internal
330
330
  def get_user_details(self, key: RegistryKey) -> UserDetails:
331
331
  """Return user details for the user who owns a registry hive that contains the provided key"""
332
- if not key.hive or not key.hive.filepath:
332
+ if not key.hive or not getattr(key.hive, "filepath", None):
333
333
  return
334
334
 
335
335
  return self._hives_to_users.get(key.hive)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.15.dev13
3
+ Version: 3.15.dev14
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
@@ -117,8 +117,10 @@ dissect/target/plugins/apps/remoteaccess/teamviewer.py,sha256=SiEH36HM2NvdPuCjfL
117
117
  dissect/target/plugins/apps/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
118
  dissect/target/plugins/apps/shell/powershell.py,sha256=biPSMRWxPI6kRqP0-75yMtrw0Ti2Bzfl_xI3xbmmF48,2641
119
119
  dissect/target/plugins/apps/ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
- dissect/target/plugins/apps/ssh/openssh.py,sha256=ebHX6_uoOHZMgHYa_MiaYjvhitrceYNjl_R71JBY5Ow,8154
121
- dissect/target/plugins/apps/ssh/opensshd.py,sha256=FWhEkaKVMAADoOO7yI2H3uHK4jmQoC4v_eOaj_4jaeY,5453
120
+ dissect/target/plugins/apps/ssh/openssh.py,sha256=jDNP8aq9JHivosexPlxWRUgeJo1MHclb336dzO1zRJc,7086
121
+ dissect/target/plugins/apps/ssh/opensshd.py,sha256=DaXKdgGF3GYHHA4buEvphcm6FF4C8YFjgD96Dv6rRnM,5510
122
+ dissect/target/plugins/apps/ssh/putty.py,sha256=N8ssjutUVN50JNA5fEIVISbP5sJ7bGTFidRbX3uNG5Y,9404
123
+ dissect/target/plugins/apps/ssh/ssh.py,sha256=uCaoWlT2bgKLUHA1aL6XymJDWJ8JmLsN8PB1C66eidY,1409
122
124
  dissect/target/plugins/apps/vpn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
125
  dissect/target/plugins/apps/vpn/openvpn.py,sha256=NZeFSFgGAifevGIQBusdbBRFOPxu0584Th8rKE-XSus,6875
124
126
  dissect/target/plugins/apps/vpn/wireguard.py,sha256=45WvCqQQGrG3DVDH5ghcsGpM_BomF4RcTLzcIvnyuNs,6554
@@ -237,7 +239,7 @@ dissect/target/plugins/os/windows/locale.py,sha256=yXVdclpUqss9h8Nq7N4kg3OHwWGDf
237
239
  dissect/target/plugins/os/windows/notifications.py,sha256=64xHHueHwtJCc8RTAF70oa0RxvqfCu_DBPWRSZBnYZc,17386
238
240
  dissect/target/plugins/os/windows/prefetch.py,sha256=5hRxdIP9sIV5Q9TAScMjLbl_mImZ37abvdE_pAd6rh4,10398
239
241
  dissect/target/plugins/os/windows/recyclebin.py,sha256=4GSj0Q3YvONufnqANbnG0ffiMQyToCiL5s35Wmu4JOQ,4898
240
- dissect/target/plugins/os/windows/registry.py,sha256=HqO8Yw2TDKhhkR7fOochzinJN_nQ4qKKx7fJ34qh7tw,12770
242
+ dissect/target/plugins/os/windows/registry.py,sha256=IBRqltJ_4fZpVuwMVCAH_nS8JUaNVjsC1jh9AZSNHL4,12788
241
243
  dissect/target/plugins/os/windows/sam.py,sha256=Es_8ROQ6R6-akuTtegCdsJHXzZJNhzgoFuS8y9xNN8E,15267
242
244
  dissect/target/plugins/os/windows/services.py,sha256=_6YkuoZD8LUxk72R3n1p1bOBab3A1wszdB1NuPavIGM,6037
243
245
  dissect/target/plugins/os/windows/sru.py,sha256=sOM7CyMkW8XIXzI75GL69WoqUrSK2X99TFIfdQR2D64,17767
@@ -306,10 +308,10 @@ dissect/target/volumes/luks.py,sha256=v_mHW05KM5iG8JDe47i2V4Q9O0r4rnAMA9m_qc9cYw
306
308
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
307
309
  dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
308
310
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
309
- dissect.target-3.15.dev13.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
310
- dissect.target-3.15.dev13.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
311
- dissect.target-3.15.dev13.dist-info/METADATA,sha256=Z8KblBmaZNzFZ5Ud5_48fnD3IyiOh2jmHhvi5ZjlH8w,11107
312
- dissect.target-3.15.dev13.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
313
- dissect.target-3.15.dev13.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
314
- dissect.target-3.15.dev13.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
315
- dissect.target-3.15.dev13.dist-info/RECORD,,
311
+ dissect.target-3.15.dev14.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
312
+ dissect.target-3.15.dev14.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
313
+ dissect.target-3.15.dev14.dist-info/METADATA,sha256=a7gsrN05qksoHcTNVGfHVUklhofWCTLyKBiNfwWLru0,11107
314
+ dissect.target-3.15.dev14.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
315
+ dissect.target-3.15.dev14.dist-info/entry_points.txt,sha256=tvFPa-Ap-gakjaPwRc6Fl6mxHzxEZ_arAVU-IUYeo_s,447
316
+ dissect.target-3.15.dev14.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
317
+ dissect.target-3.15.dev14.dist-info/RECORD,,