dissect.target 3.19.dev27__py3-none-any.whl → 3.19.dev29__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.
@@ -3,6 +3,7 @@ import json
3
3
  import logging
4
4
  from base64 import b64decode
5
5
  from hashlib import pbkdf2_hmac, sha1
6
+ from itertools import chain
6
7
  from typing import Iterator, Optional
7
8
 
8
9
  from dissect.sql import sqlite3
@@ -14,7 +15,7 @@ from dissect.target.exceptions import FileNotFoundError, UnsupportedPluginError
14
15
  from dissect.target.helpers.descriptor_extensions import UserRecordDescriptorExtension
15
16
  from dissect.target.helpers.fsutil import TargetPath
16
17
  from dissect.target.helpers.record import create_extended_descriptor
17
- from dissect.target.plugin import export
18
+ from dissect.target.plugin import OperatingSystem, export
18
19
  from dissect.target.plugins.apps.browser.browser import (
19
20
  GENERIC_COOKIE_FIELDS,
20
21
  GENERIC_DOWNLOAD_RECORD_FIELDS,
@@ -24,7 +25,7 @@ from dissect.target.plugins.apps.browser.browser import (
24
25
  BrowserPlugin,
25
26
  try_idna,
26
27
  )
27
- from dissect.target.plugins.general.users import UserDetails
28
+ from dissect.target.plugins.general.users import UserRecord
28
29
 
29
30
  try:
30
31
  from asn1crypto import algos, core
@@ -44,7 +45,10 @@ try:
44
45
  except ImportError:
45
46
  HAS_CRYPTO = False
46
47
 
47
- FIREFOX_EXTENSION_RECORD_FIELDS = [("uri", "source_uri"), ("string[]", "optional_permissions")]
48
+ FIREFOX_EXTENSION_RECORD_FIELDS = [
49
+ ("uri", "source_uri"),
50
+ ("string[]", "optional_permissions"),
51
+ ]
48
52
 
49
53
  log = logging.getLogger(__name__)
50
54
 
@@ -54,7 +58,7 @@ class FirefoxPlugin(BrowserPlugin):
54
58
 
55
59
  __namespace__ = "firefox"
56
60
 
57
- DIRS = [
61
+ USER_DIRS = [
58
62
  # Windows
59
63
  "AppData/Roaming/Mozilla/Firefox/Profiles",
60
64
  "AppData/local/Mozilla/Firefox/Profiles",
@@ -66,6 +70,10 @@ class FirefoxPlugin(BrowserPlugin):
66
70
  "Library/Application Support/Firefox",
67
71
  ]
68
72
 
73
+ SYSTEM_DIRS = [
74
+ "/data/data/org.mozilla.vrbrowser/files/mozilla",
75
+ ]
76
+
69
77
  BrowserHistoryRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
70
78
  "browser/firefox/history", GENERIC_HISTORY_RECORD_FIELDS
71
79
  )
@@ -79,7 +87,8 @@ class FirefoxPlugin(BrowserPlugin):
79
87
  )
80
88
 
81
89
  BrowserExtensionRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
82
- "browser/firefox/extension", GENERIC_EXTENSION_RECORD_FIELDS + FIREFOX_EXTENSION_RECORD_FIELDS
90
+ "browser/firefox/extension",
91
+ GENERIC_EXTENSION_RECORD_FIELDS + FIREFOX_EXTENSION_RECORD_FIELDS,
83
92
  )
84
93
 
85
94
  BrowserPasswordRecord = create_extended_descriptor([UserRecordDescriptorExtension])(
@@ -88,27 +97,32 @@ class FirefoxPlugin(BrowserPlugin):
88
97
 
89
98
  def __init__(self, target):
90
99
  super().__init__(target)
91
- self.users_dirs: list[tuple[UserDetails, TargetPath]] = []
100
+ self.dirs: list[tuple[UserRecord, TargetPath]] = []
101
+
92
102
  for user_details in self.target.user_details.all_with_home():
93
- for directory in self.DIRS:
103
+ for directory in self.USER_DIRS:
94
104
  cur_dir = user_details.home_path.joinpath(directory)
95
105
  if not cur_dir.exists():
96
106
  continue
97
- self.users_dirs.append((user_details, cur_dir))
107
+ self.dirs.append((user_details.user, cur_dir))
108
+
109
+ for directory in self.SYSTEM_DIRS:
110
+ if (cur_dir := target.fs.path(directory)).exists():
111
+ self.dirs.append((None, cur_dir))
98
112
 
99
113
  def check_compatible(self) -> None:
100
- if not len(self.users_dirs):
114
+ if not len(self.dirs):
101
115
  raise UnsupportedPluginError("No Firefox directories found")
102
116
 
103
- def _iter_profiles(self) -> Iterator[tuple[UserDetails, TargetPath, TargetPath]]:
117
+ def _iter_profiles(self) -> Iterator[tuple[UserRecord, TargetPath, TargetPath]]:
104
118
  """Yield user directories."""
105
- for user, cur_dir in self.users_dirs:
119
+ for user, cur_dir in self.dirs:
106
120
  for profile_dir in cur_dir.iterdir():
107
121
  if not profile_dir.is_dir():
108
122
  continue
109
123
  yield user, cur_dir, profile_dir
110
124
 
111
- def _iter_db(self, filename: str) -> Iterator[tuple[UserDetails, SQLite3]]:
125
+ def _iter_db(self, filename: str) -> Iterator[tuple[UserRecord, SQLite3]]:
112
126
  """Yield opened history database files of all users.
113
127
 
114
128
  Args:
@@ -117,12 +131,24 @@ class FirefoxPlugin(BrowserPlugin):
117
131
  Yields:
118
132
  Opened SQLite3 databases.
119
133
  """
120
- for user, cur_dir, profile_dir in self._iter_profiles():
121
- db_file = profile_dir.joinpath(filename)
134
+ iter_system = ((None, system_dir, None) for user, system_dir in self.dirs if user is None)
135
+
136
+ for user, cur_dir, profile_dir in chain(iter_system, self._iter_profiles()):
137
+ if user is None and profile_dir is None:
138
+ db_file = cur_dir.parent.joinpath(filename)
139
+ # On some Android variants, some files may exist in the base directory (places.sqlite) but others
140
+ # in a nested profile directory (cookies.sqlite)
141
+ # /data/data/org.mozilla.vrbrowser/files/places.sqlite
142
+ # /data/data/org.mozilla.vrbrowser/files/mozilla/xxxxxx.default/cookies.sqlite
143
+ if not db_file.exists():
144
+ continue
145
+ else:
146
+ db_file = profile_dir.joinpath(filename)
147
+
122
148
  try:
123
149
  yield user, db_file, sqlite3.SQLite3(db_file.open())
124
150
  except FileNotFoundError:
125
- self.target.log.warning("Could not find %s file: %s", filename, db_file)
151
+ self.target.log.info("Could not find %s file: %s", filename, db_file)
126
152
  except SQLError as e:
127
153
  self.target.log.warning("Could not open %s file: %s", filename, db_file)
128
154
  self.target.log.debug("", exc_info=e)
@@ -151,6 +177,11 @@ class FirefoxPlugin(BrowserPlugin):
151
177
  from_url (uri): URL of the "from" visit.
152
178
  source: (path): The source file of the history record.
153
179
  """
180
+ if self.target.os == OperatingSystem.ANDROID:
181
+ from_timestamp = from_unix_ms
182
+ else:
183
+ from_timestamp = from_unix_us
184
+
154
185
  for user, db_file, db in self._iter_db("places.sqlite"):
155
186
  try:
156
187
  places = {row.id: row for row in db.table("moz_places").rows()}
@@ -167,7 +198,7 @@ class FirefoxPlugin(BrowserPlugin):
167
198
  from_visit, from_place = None, None
168
199
 
169
200
  yield self.BrowserHistoryRecord(
170
- ts=from_unix_us(row.visit_date),
201
+ ts=from_timestamp(row.visit_date),
171
202
  browser="firefox",
172
203
  id=row.id,
173
204
  url=try_idna(place.url),
@@ -183,7 +214,7 @@ class FirefoxPlugin(BrowserPlugin):
183
214
  from_url=try_idna(from_place.url) if from_place else None,
184
215
  source=db_file,
185
216
  _target=self.target,
186
- _user=user.user,
217
+ _user=user,
187
218
  )
188
219
  except SQLError as e:
189
220
  self.target.log.warning("Error processing history file: %s", db_file, exc_info=e)
@@ -229,7 +260,7 @@ class FirefoxPlugin(BrowserPlugin):
229
260
  same_site=bool(cookie.sameSite),
230
261
  source=db_file,
231
262
  _target=self.target,
232
- _user=user.user,
263
+ _user=user,
233
264
  )
234
265
  except SQLError as e:
235
266
  self.target.log.warning("Error processing cookie file: %s", db_file, exc_info=e)
@@ -255,7 +286,10 @@ class FirefoxPlugin(BrowserPlugin):
255
286
  for user, db_file, db in self._iter_db("places.sqlite"):
256
287
  try:
257
288
  places = {row.id: row for row in db.table("moz_places").rows()}
258
- attributes = {row.id: row.name for row in db.table("moz_anno_attributes").rows()}
289
+ if not (moz_anno_attributes := db.table("moz_anno_attributes")):
290
+ continue
291
+
292
+ attributes = {row.id: row.name for row in moz_anno_attributes.rows()}
259
293
  annotations = {}
260
294
 
261
295
  for row in db.table("moz_annos"):
@@ -316,7 +350,7 @@ class FirefoxPlugin(BrowserPlugin):
316
350
  state=state,
317
351
  source=db_file,
318
352
  _target=self.target,
319
- _user=user.user,
353
+ _user=user,
320
354
  )
321
355
  except SQLError as e:
322
356
  self.target.log.warning("Error processing history file: %s", db_file, exc_info=e)
@@ -351,7 +385,9 @@ class FirefoxPlugin(BrowserPlugin):
351
385
 
352
386
  if not extension_file.exists():
353
387
  self.target.log.warning(
354
- "No 'extensions.json' addon file found for user %s in directory %s", user.user.name, profile_dir
388
+ "No 'extensions.json' addon file found for user %s in directory %s",
389
+ user.name,
390
+ profile_dir,
355
391
  )
356
392
  continue
357
393
 
@@ -360,8 +396,8 @@ class FirefoxPlugin(BrowserPlugin):
360
396
 
361
397
  for extension in extensions.get("addons", []):
362
398
  yield self.BrowserExtensionRecord(
363
- ts_install=extension.get("installDate", 0) // 1000,
364
- ts_update=extension.get("updateDate", 0) // 1000,
399
+ ts_install=from_unix_ms(extension.get("installDate", 0)),
400
+ ts_update=from_unix_ms(extension.get("updateDate", 0)),
365
401
  browser="firefox",
366
402
  id=extension.get("id"),
367
403
  name=(extension.get("defaultLocale", {}) or {}).get("name"),
@@ -377,12 +413,14 @@ class FirefoxPlugin(BrowserPlugin):
377
413
  optional_permissions=(extension.get("optionalPermissions", {}) or {}).get("permissions"),
378
414
  source=extension_file,
379
415
  _target=self.target,
380
- _user=user.user,
416
+ _user=user,
381
417
  )
382
418
 
383
419
  except FileNotFoundError:
384
420
  self.target.log.info(
385
- "No 'extensions.json' addon file found for user %s in directory %s", user.user.name, profile_dir
421
+ "No 'extensions.json' addon file found for user %s in directory %s",
422
+ user.name,
423
+ profile_dir,
386
424
  )
387
425
  except json.JSONDecodeError:
388
426
  self.target.log.warning(
@@ -410,7 +448,9 @@ class FirefoxPlugin(BrowserPlugin):
410
448
 
411
449
  if not login_file.exists():
412
450
  self.target.log.warning(
413
- "No 'logins.json' password file found for user %s in directory %s", user, profile_dir
451
+ "No 'logins.json' password file found for user %s in directory %s",
452
+ user.name,
453
+ profile_dir,
414
454
  )
415
455
  continue
416
456
 
@@ -445,9 +485,9 @@ class FirefoxPlugin(BrowserPlugin):
445
485
  break
446
486
 
447
487
  yield self.BrowserPasswordRecord(
448
- ts_created=login.get("timeCreated", 0) // 1000,
449
- ts_last_used=login.get("timeLastUsed", 0) // 1000,
450
- ts_last_changed=login.get("timePasswordChanged", 0) // 1000,
488
+ ts_created=from_unix_ms(login.get("timeCreated", 0)),
489
+ ts_last_used=from_unix_ms(login.get("timeLastUsed", 0)),
490
+ ts_last_changed=from_unix_ms(login.get("timePasswordChanged", 0)),
451
491
  browser="firefox",
452
492
  id=login.get("id"),
453
493
  url=login.get("hostname"),
@@ -457,14 +497,19 @@ class FirefoxPlugin(BrowserPlugin):
457
497
  decrypted_password=decrypted_password,
458
498
  source=login_file,
459
499
  _target=self.target,
460
- _user=user.user,
500
+ _user=user,
461
501
  )
462
502
 
463
503
  except FileNotFoundError:
464
- self.target.log.info("No password file found for user %s in directory %s", user, profile_dir)
504
+ self.target.log.info(
505
+ "No password file found for user %s in directory %s",
506
+ user.name,
507
+ profile_dir,
508
+ )
465
509
  except json.JSONDecodeError:
466
510
  self.target.log.warning(
467
- "logins.json file in directory %s is malformed, consider inspecting the file manually", profile_dir
511
+ "logins.json file in directory %s is malformed, consider inspecting the file manually",
512
+ profile_dir,
468
513
  )
469
514
 
470
515
 
@@ -76,17 +76,15 @@ class YaraPlugin(Plugin):
76
76
  if hasattr(compiled_rules, "warnings") and (num_warns := len(compiled_rules.warnings)) > 0:
77
77
  self.target.log.warning("YARA generated %s warnings while compiling rules", num_warns)
78
78
  for warning in compiled_rules.warnings:
79
- self.target.log.debug(warning)
79
+ self.target.log.info(warning)
80
80
 
81
81
  self.target.log.warning("Will not scan files larger than %s MB", max_size // 1024 // 1024)
82
82
 
83
83
  for _, _, files in self.target.fs.walk_ext(path):
84
84
  for file in files:
85
85
  try:
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
- )
86
+ if (file_size := file.stat().st_size) > max_size:
87
+ self.target.log.info("Not scanning file of %s MB: '%s'", (file_size // 1024 // 1024), file)
90
88
  continue
91
89
 
92
90
  buf = file.open().read()
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from functools import lru_cache
2
- from typing import Generator, NamedTuple, Optional, Union
4
+ from typing import Iterator, NamedTuple, Union
3
5
 
4
6
  from dissect.target import Target
5
7
  from dissect.target.exceptions import UnsupportedPluginError
@@ -7,10 +9,12 @@ from dissect.target.helpers.fsutil import TargetPath
7
9
  from dissect.target.helpers.record import UnixUserRecord, WindowsUserRecord
8
10
  from dissect.target.plugin import InternalPlugin
9
11
 
12
+ UserRecord = Union[UnixUserRecord, WindowsUserRecord]
13
+
10
14
 
11
15
  class UserDetails(NamedTuple):
12
- user: Union[UnixUserRecord, WindowsUserRecord]
13
- home_path: Optional[TargetPath]
16
+ user: UserRecord
17
+ home_path: TargetPath | None
14
18
 
15
19
 
16
20
  class UsersPlugin(InternalPlugin):
@@ -28,11 +32,11 @@ class UsersPlugin(InternalPlugin):
28
32
 
29
33
  def find(
30
34
  self,
31
- sid: Optional[str] = None,
32
- uid: Optional[str] = None,
33
- username: Optional[str] = None,
35
+ sid: str | None = None,
36
+ uid: str | None = None,
37
+ username: str | None = None,
34
38
  force_case_sensitive: bool = False,
35
- ) -> Optional[UserDetails]:
39
+ ) -> UserDetails | None:
36
40
  """Find User record matching provided sid, uid or username and return UserDetails object"""
37
41
  if all(map(lambda x: x is None, [sid, uid, username])):
38
42
  raise ValueError("Either sid or uid or username is expected")
@@ -52,7 +56,7 @@ class UsersPlugin(InternalPlugin):
52
56
  ):
53
57
  return self.get(user)
54
58
 
55
- def get(self, user: Union[UnixUserRecord, WindowsUserRecord]) -> UserDetails:
59
+ def get(self, user: UserRecord) -> UserDetails:
56
60
  """Return additional details about the user"""
57
61
  # Resolving the user home can not use the user's environment variables,
58
62
  # as those depend on the user's home to be known first. So we resolve
@@ -60,12 +64,12 @@ class UsersPlugin(InternalPlugin):
60
64
  home_path = self.target.fs.path(self.target.resolve(str(user.home))) if user.home else None
61
65
  return UserDetails(user=user, home_path=home_path)
62
66
 
63
- def all(self) -> Generator[UserDetails, None, None]:
67
+ def all(self) -> Iterator[UserDetails]:
64
68
  """Return UserDetails objects for all users found"""
65
69
  for user in self.target.users():
66
70
  yield self.get(user)
67
71
 
68
- def all_with_home(self) -> Generator[UserDetails, None, None]:
72
+ def all_with_home(self) -> Iterator[UserDetails]:
69
73
  """Return UserDetails objects for users that have existing directory set as home directory"""
70
74
  for user in self.target.users():
71
75
  if user.home:
dissect/target/target.py CHANGED
@@ -344,7 +344,7 @@ class Target:
344
344
  child_plugin.check_compatible()
345
345
  self._child_plugins[child_plugin.__type__] = child_plugin
346
346
  except PluginError as e:
347
- self.log.info("Child plugin reported itself as incompatible: %s (%s)", plugin_desc["class"], e)
347
+ self.log.debug("Child plugin reported itself as incompatible: %s (%s)", plugin_desc["class"], e)
348
348
  except Exception:
349
349
  self.log.exception(
350
350
  "An exception occurred while checking for child plugin compatibility: %s", plugin_desc["class"]
@@ -27,6 +27,7 @@ def main():
27
27
 
28
28
  parser.add_argument("targets", metavar="TARGETS", nargs="*", help="Targets to load")
29
29
  parser.add_argument("-s", "--strings", default=False, action="store_true", help="print output as string")
30
+ parser.add_argument("--children", action="store_true", help="include children")
30
31
 
31
32
  for args, kwargs in getattr(YaraPlugin.yara, "__args__", []):
32
33
  parser.add_argument(*args, **kwargs)
@@ -45,8 +46,7 @@ def main():
45
46
  parser.exit(1)
46
47
 
47
48
  try:
48
- for target in Target.open_all(args.targets):
49
- target.log.info("Scanning target")
49
+ for target in Target.open_all(args.targets, args.children):
50
50
  rs = record_output(args.strings, False)
51
51
  for record in target.yara(args.rules, args.path, args.max_size, args.check):
52
52
  rs.write(record)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.19.dev27
3
+ Version: 3.19.dev29
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=8vg0VdEQuy5Ih5ewlm0b64o3HcJq_Nley4Ygyp2fLI4,32362
8
+ dissect/target/target.py,sha256=KZ3vDsMjrXxEP6sQE1kOlxMNjqFFsxnivYhoX26GBEY,32363
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
@@ -124,7 +124,7 @@ dissect/target/plugins/apps/browser/browser.py,sha256=rBIwcgdl73gm-8APwx2jEUAYXR
124
124
  dissect/target/plugins/apps/browser/chrome.py,sha256=DMONTYE95sI_jcmyQOapHwWQWwrezfYMllVCCPwhEP0,3117
125
125
  dissect/target/plugins/apps/browser/chromium.py,sha256=V08Hq8GHMPd7snynh5RKQl4YHlhtwmlMsodLZeOnf_4,28103
126
126
  dissect/target/plugins/apps/browser/edge.py,sha256=tuuIbm4s8nNstA6nIOEfU0LG0jt20a8gf3rve2SXtdM,2953
127
- dissect/target/plugins/apps/browser/firefox.py,sha256=PmSTVSqimigA89hRcYMB4vNYXe3IwnTm_fLf4NhRbUo,31026
127
+ dissect/target/plugins/apps/browser/firefox.py,sha256=mZBBagFfIdiz9kUyK4Hi989I4g3CWrClBbmpaGMRKxg,32472
128
128
  dissect/target/plugins/apps/browser/iexplore.py,sha256=g_xw0toaiyjevxO8g9XPCOqc-CXZp39FVquRhPFGdTE,8801
129
129
  dissect/target/plugins/apps/container/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
130
  dissect/target/plugins/apps/container/docker.py,sha256=KxQRbKGgxkf3YFBMa7fjeJ7qo8qjFys7zEmfQhDTnLw,15305
@@ -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=JdWqbqDBhKrht3fTroqX7NpBU9khEQUWyMcDgLv2l2g,6686
167
+ dissect/target/plugins/filesystem/yara.py,sha256=w9kJ8trua0rhcpaN18erc0vGIFsJJeqaV6y5lMRl8JQ,6611
168
168
  dissect/target/plugins/filesystem/ntfs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
169
  dissect/target/plugins/filesystem/ntfs/mft.py,sha256=2ibCLJA7yUrZshFSPKdjoNt3TpfwTtk-DaErghe91CM,11445
170
170
  dissect/target/plugins/filesystem/ntfs/mft_timeline.py,sha256=vvNFAZbr7s3X2OTYf4ES_L6-XsouTXcTymfxnHfZ1Rw,6791
@@ -181,7 +181,7 @@ dissect/target/plugins/general/loaders.py,sha256=6iUxhlSAgo7qSE8_XFxgiihK8sdMiP-
181
181
  dissect/target/plugins/general/osinfo.py,sha256=RdK5mw3-H9H3sGXz8yP8U_p3wUG1Ww7_HBKZpFdsbTE,1358
182
182
  dissect/target/plugins/general/plugins.py,sha256=4URjS6DN1Ey6Cqlbyx6NfFGgQZpWDrqxl8KLcZFODGE,4479
183
183
  dissect/target/plugins/general/scrape.py,sha256=Fz7BNXflvuxlnVulyyDhLpyU8D_hJdH6vWVtER9vjTg,6651
184
- dissect/target/plugins/general/users.py,sha256=cQXPQ2XbkPjckCPHYTUW4JEhYN0_CT8JI8hJPZn3qSs,3030
184
+ dissect/target/plugins/general/users.py,sha256=yy9gvRXfN9BT71v4Xqo5hpwfgN9he9Otu8TBPZ_Tegs,3009
185
185
  dissect/target/plugins/os/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
186
186
  dissect/target/plugins/os/unix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
187
187
  dissect/target/plugins/os/unix/_os.py,sha256=u7m97qASdm_l90k4i7dzMtu2kcF6fVPKutx4_ISQTSg,14606
@@ -333,7 +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
+ dissect/target/tools/yara.py,sha256=SZ0lKshWJ0TFTDUYONVKF04TgwmtDAttUPws9j9YSvk,1806
337
337
  dissect/target/tools/dump/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
338
338
  dissect/target/tools/dump/run.py,sha256=aD84peRS4zHqC78fH7Vd4ni3m1ZmVP70LyMwBRvoDGY,9463
339
339
  dissect/target/tools/dump/state.py,sha256=YYgCff0kZZ-tx27lJlc9LQ7AfoGnLK5Gyi796OnktA8,9205
@@ -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.dev27.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
350
- dissect.target-3.19.dev27.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
351
- dissect.target-3.19.dev27.dist-info/METADATA,sha256=3UjjqXN9S8KdCdNsMV94sM_4m6LXWtM5VtdDeNDpVi0,12719
352
- dissect.target-3.19.dev27.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
353
- dissect.target-3.19.dev27.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
354
- dissect.target-3.19.dev27.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
355
- dissect.target-3.19.dev27.dist-info/RECORD,,
349
+ dissect.target-3.19.dev29.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
350
+ dissect.target-3.19.dev29.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
351
+ dissect.target-3.19.dev29.dist-info/METADATA,sha256=mE32WDUFrARni26ZPIFtiWS3iHI51FCZBoIz4IVFVL4,12719
352
+ dissect.target-3.19.dev29.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
353
+ dissect.target-3.19.dev29.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
354
+ dissect.target-3.19.dev29.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
355
+ dissect.target-3.19.dev29.dist-info/RECORD,,