dissect.target 3.20.dev36__py3-none-any.whl → 3.20.dev39__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. dissect/target/filesystems/config.py +1 -1
  2. dissect/target/helpers/compat/path_common.py +5 -5
  3. dissect/target/helpers/configutil.py +31 -29
  4. dissect/target/helpers/cyber.py +2 -0
  5. dissect/target/helpers/docs.py +1 -1
  6. dissect/target/helpers/keychain.py +2 -0
  7. dissect/target/helpers/mount.py +2 -1
  8. dissect/target/plugin.py +15 -13
  9. dissect/target/plugins/apps/av/mcafee.py +2 -0
  10. dissect/target/plugins/apps/av/sophos.py +2 -0
  11. dissect/target/plugins/apps/av/trendmicro.py +2 -0
  12. dissect/target/plugins/apps/browser/chromium.py +27 -6
  13. dissect/target/plugins/apps/editor/editor.py +23 -0
  14. dissect/target/plugins/apps/{texteditor → editor}/windowsnotepad.py +40 -31
  15. dissect/target/plugins/apps/shell/powershell.py +6 -2
  16. dissect/target/plugins/apps/shell/wget.py +1 -1
  17. dissect/target/plugins/apps/ssh/openssh.py +2 -0
  18. dissect/target/plugins/apps/ssh/opensshd.py +2 -0
  19. dissect/target/plugins/apps/vpn/wireguard.py +9 -9
  20. dissect/target/plugins/apps/webhosting/cpanel.py +2 -0
  21. dissect/target/plugins/apps/webserver/caddy.py +2 -0
  22. dissect/target/plugins/apps/webserver/nginx.py +2 -0
  23. dissect/target/plugins/child/esxi.py +3 -1
  24. dissect/target/plugins/child/virtuozzo.py +12 -8
  25. dissect/target/plugins/filesystem/acquire_hash.py +2 -1
  26. dissect/target/plugins/filesystem/icat.py +15 -11
  27. dissect/target/plugins/filesystem/ntfs/mft.py +2 -0
  28. dissect/target/plugins/filesystem/ntfs/mft_timeline.py +3 -1
  29. dissect/target/plugins/filesystem/ntfs/usnjrnl.py +2 -0
  30. dissect/target/plugins/filesystem/ntfs/utils.py +3 -1
  31. dissect/target/plugins/filesystem/unix/suid.py +4 -1
  32. dissect/target/plugins/filesystem/walkfs.py +2 -0
  33. dissect/target/plugins/general/example.py +2 -2
  34. dissect/target/plugins/general/loaders.py +1 -1
  35. dissect/target/plugins/general/network.py +7 -0
  36. dissect/target/plugins/general/osinfo.py +1 -0
  37. dissect/target/plugins/general/plugins.py +4 -0
  38. dissect/target/plugins/os/unix/_os.py +2 -1
  39. dissect/target/plugins/os/unix/bsd/citrix/history.py +2 -0
  40. dissect/target/plugins/os/unix/bsd/osx/network.py +2 -0
  41. dissect/target/plugins/os/unix/bsd/osx/user.py +4 -0
  42. dissect/target/plugins/os/unix/cronjobs.py +8 -4
  43. dissect/target/plugins/os/unix/etc/etc.py +4 -0
  44. dissect/target/plugins/os/unix/generic.py +2 -0
  45. dissect/target/plugins/os/unix/history.py +27 -25
  46. dissect/target/plugins/os/unix/linux/cmdline.py +2 -0
  47. dissect/target/plugins/os/unix/linux/debian/apt.py +4 -1
  48. dissect/target/plugins/os/unix/linux/debian/dpkg.py +3 -3
  49. dissect/target/plugins/os/unix/linux/environ.py +2 -0
  50. dissect/target/plugins/os/unix/linux/fortios/generic.py +2 -0
  51. dissect/target/plugins/os/unix/linux/fortios/locale.py +2 -0
  52. dissect/target/plugins/os/unix/linux/modules.py +2 -0
  53. dissect/target/plugins/os/unix/linux/netstat.py +2 -0
  54. dissect/target/plugins/os/unix/linux/processes.py +2 -0
  55. dissect/target/plugins/os/unix/linux/redhat/yum.py +4 -1
  56. dissect/target/plugins/os/unix/linux/services.py +5 -3
  57. dissect/target/plugins/os/unix/linux/sockets.py +2 -0
  58. dissect/target/plugins/os/unix/linux/suse/zypper.py +4 -1
  59. dissect/target/plugins/os/unix/locale.py +2 -0
  60. dissect/target/plugins/os/unix/locate/gnulocate.py +4 -2
  61. dissect/target/plugins/os/unix/locate/mlocate.py +2 -0
  62. dissect/target/plugins/os/unix/locate/plocate.py +3 -1
  63. dissect/target/plugins/os/unix/log/atop.py +2 -0
  64. dissect/target/plugins/os/unix/log/audit.py +3 -1
  65. dissect/target/plugins/os/unix/log/auth.py +4 -2
  66. dissect/target/plugins/os/unix/log/lastlog.py +5 -3
  67. dissect/target/plugins/os/unix/log/messages.py +2 -0
  68. dissect/target/plugins/os/unix/log/utmp.py +4 -2
  69. dissect/target/plugins/os/unix/packagemanager.py +4 -37
  70. dissect/target/plugins/os/unix/shadow.py +3 -1
  71. dissect/target/plugins/os/unix/trash.py +1 -1
  72. dissect/target/plugins/os/windows/activitiescache.py +9 -4
  73. dissect/target/plugins/os/windows/adpolicy.py +2 -1
  74. dissect/target/plugins/os/windows/amcache.py +16 -13
  75. dissect/target/plugins/os/windows/defender.py +3 -3
  76. dissect/target/plugins/os/windows/dpapi/keyprovider/credhist.py +3 -0
  77. dissect/target/plugins/os/windows/dpapi/keyprovider/empty.py +3 -0
  78. dissect/target/plugins/os/windows/dpapi/keyprovider/keychain.py +3 -0
  79. dissect/target/plugins/os/windows/dpapi/keyprovider/lsa.py +3 -0
  80. dissect/target/plugins/os/windows/env.py +1 -2
  81. dissect/target/plugins/os/windows/exchange/exchange.py +6 -4
  82. dissect/target/plugins/os/windows/generic.py +20 -18
  83. dissect/target/plugins/os/windows/lnk.py +2 -0
  84. dissect/target/plugins/os/windows/locale.py +9 -3
  85. dissect/target/plugins/os/windows/log/etl.py +5 -4
  86. dissect/target/plugins/os/windows/log/evt.py +12 -8
  87. dissect/target/plugins/os/windows/log/evtx.py +9 -7
  88. dissect/target/plugins/os/windows/log/pfro.py +2 -1
  89. dissect/target/plugins/os/windows/network.py +2 -0
  90. dissect/target/plugins/os/windows/notifications.py +6 -4
  91. dissect/target/plugins/os/windows/prefetch.py +7 -2
  92. dissect/target/plugins/os/windows/regf/7zip.py +9 -1
  93. dissect/target/plugins/os/windows/regf/auditpol.py +2 -1
  94. dissect/target/plugins/os/windows/regf/bam.py +3 -1
  95. dissect/target/plugins/os/windows/regf/cit.py +14 -12
  96. dissect/target/plugins/os/windows/regf/clsid.py +6 -3
  97. dissect/target/plugins/os/windows/regf/firewall.py +2 -1
  98. dissect/target/plugins/os/windows/regf/mru.py +9 -8
  99. dissect/target/plugins/os/windows/regf/nethist.py +6 -3
  100. dissect/target/plugins/os/windows/regf/recentfilecache.py +3 -1
  101. dissect/target/plugins/os/windows/regf/regf.py +5 -1
  102. dissect/target/plugins/os/windows/regf/shimcache.py +1 -1
  103. dissect/target/plugins/os/windows/regf/usb.py +2 -1
  104. dissect/target/plugins/os/windows/regf/userassist.py +2 -1
  105. dissect/target/plugins/os/windows/registry.py +11 -0
  106. dissect/target/plugins/os/windows/services.py +3 -2
  107. dissect/target/plugins/os/windows/startupinfo.py +7 -2
  108. dissect/target/plugins/os/windows/syscache.py +3 -1
  109. dissect/target/plugins/os/windows/tasks.py +1 -1
  110. dissect/target/plugins/os/windows/thumbcache.py +11 -5
  111. dissect/target/plugins/os/windows/ual.py +12 -9
  112. dissect/target/plugins/os/windows/wua_history.py +0 -1
  113. dissect/target/tools/dump/utils.py +4 -0
  114. dissect/target/tools/shell.py +2 -1
  115. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/METADATA +1 -1
  116. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/RECORD +122 -123
  117. dissect/target/plugins/apps/texteditor/texteditor.py +0 -13
  118. dissect/target/plugins/os/unix/etc.py +0 -9
  119. /dissect/target/plugins/apps/{texteditor → editor}/__init__.py +0 -0
  120. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/COPYRIGHT +0 -0
  121. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/LICENSE +0 -0
  122. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/WHEEL +0 -0
  123. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/entry_points.txt +0 -0
  124. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  import struct
2
+ from typing import Iterator
2
3
 
3
4
  from dissect.util.ts import wintimestamp
4
5
 
@@ -121,7 +122,7 @@ class MRUPlugin(Plugin):
121
122
  return UnsupportedPluginError("Target has no registry")
122
123
 
123
124
  @export(record=RunMRURecord)
124
- def run(self):
125
+ def run(self) -> Iterator[RunMRURecord]:
125
126
  """Return the RunMRU data.
126
127
 
127
128
  The ``HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU`` registry key contains information
@@ -136,7 +137,7 @@ class MRUPlugin(Plugin):
136
137
  yield from parse_mru_key(self.target, key, RunMRURecord)
137
138
 
138
139
  @export(record=RecentDocsRecord)
139
- def recentdocs(self):
140
+ def recentdocs(self) -> Iterator[RecentDocsRecord]:
140
141
  """Return the RecentDocs data.
141
142
 
142
143
  The ``HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs`` registry key contains
@@ -153,7 +154,7 @@ class MRUPlugin(Plugin):
153
154
  yield from parse_mru_ex_key(self.target, key, RecentDocsRecord)
154
155
 
155
156
  @export(record=OpenSaveMRURecord)
156
- def opensave(self):
157
+ def opensave(self) -> Iterator[OpenSaveMRURecord]:
157
158
  """Return the OpenSaveMRU data.
158
159
 
159
160
  The ``HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\OpenSaveMRU`` registry key
@@ -169,7 +170,7 @@ class MRUPlugin(Plugin):
169
170
  yield from parse_mru_key(self.target, key, OpenSaveMRURecord)
170
171
 
171
172
  @export(record=LastVisitedMRURecord)
172
- def lastvisited(self):
173
+ def lastvisited(self) -> Iterator[LastVisitedMRURecord]:
173
174
  """Return the LastVisitedMRU data.
174
175
 
175
176
  The ``HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU`` registry key
@@ -210,7 +211,7 @@ class MRUPlugin(Plugin):
210
211
  )
211
212
 
212
213
  @export(record=ACMruRecord)
213
- def acmru(self):
214
+ def acmru(self) -> Iterator[ACMruRecord]:
214
215
  """Return the ACMru (Windows Search) data.
215
216
 
216
217
  The following keys are being searched:
@@ -252,7 +253,7 @@ class MRUPlugin(Plugin):
252
253
  yield from parse_mru_ex_key(self.target, key, ACMruRecord)
253
254
 
254
255
  @export(record=MapNetworkDriveMRURecord)
255
- def networkdrive(self):
256
+ def networkdrive(self) -> Iterator[MapNetworkDriveMRURecord]:
256
257
  """Return MRU of mapped network drives.
257
258
 
258
259
  The HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Map Network Drive MRU registry key contains
@@ -268,7 +269,7 @@ class MRUPlugin(Plugin):
268
269
  yield from parse_mru_key(self.target, key, MapNetworkDriveMRURecord)
269
270
 
270
271
  @export(record=TerminalServerMRURecord)
271
- def mstsc(self):
272
+ def mstsc(self) -> Iterator[TerminalServerMRURecord]:
272
273
  """Return Terminal Server Client MRU data."""
273
274
 
274
275
  KEY = "HKCU\\Software\\Microsoft\\Terminal Server Client\\Default"
@@ -290,7 +291,7 @@ class MRUPlugin(Plugin):
290
291
  )
291
292
 
292
293
  @export(record=MSOfficeMRURecord)
293
- def msoffice(self):
294
+ def msoffice(self) -> Iterator[MSOfficeMRURecord]:
294
295
  """Return MS Office MRU keys."""
295
296
 
296
297
  KEY = "HKCU\\Software\\Microsoft\\Office"
@@ -1,5 +1,6 @@
1
1
  import datetime
2
2
  import struct
3
+ from typing import Iterator
3
4
 
4
5
  from dissect.target.exceptions import RegistryError, UnsupportedPluginError
5
6
  from dissect.target.helpers.record import TargetRecordDescriptor
@@ -22,6 +23,8 @@ NetworkHistoryRecord = TargetRecordDescriptor(
22
23
 
23
24
 
24
25
  class NethistPlugin(Plugin):
26
+ """Windows network history plugin."""
27
+
25
28
  KEY = "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Networklist\\Signatures"
26
29
  PROFILE_KEY = "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Networklist\\Profiles"
27
30
 
@@ -30,7 +33,7 @@ class NethistPlugin(Plugin):
30
33
  raise UnsupportedPluginError("No Networklist registry keys found")
31
34
 
32
35
  @export(record=NetworkHistoryRecord)
33
- def network_history(self):
36
+ def network_history(self) -> Iterator[NetworkHistoryRecord]:
34
37
  """Return attached network history.
35
38
 
36
39
  The HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Networklist\\Signatures and
@@ -38,8 +41,8 @@ class NethistPlugin(Plugin):
38
41
  about the networks to which the system has been connected, both wireless and wired.
39
42
 
40
43
  References:
41
- - https://www.weaklink.org/2016/11/windows-network-profile-registry-keys/
42
- """
44
+ - https://web.archive.org/web/20221127181357/https://www.weaklink.org/2016/11/windows-network-profile-registry-keys/
45
+ """ # noqa: E501
43
46
  for key in self.target.registry.keys(self.KEY):
44
47
  for kind in key.subkeys():
45
48
  for sig in kind.subkeys():
@@ -1,3 +1,5 @@
1
+ from typing import Iterator
2
+
1
3
  from dissect.cstruct import cstruct
2
4
 
3
5
  from dissect.target.exceptions import UnsupportedPluginError
@@ -40,7 +42,7 @@ class RecentFileCachePlugin(Plugin):
40
42
  raise UnsupportedPluginError("Could not load RecentFileCache.bcf")
41
43
 
42
44
  @export(record=RecentFileCacheRecord)
43
- def recentfilecache(self):
45
+ def recentfilecache(self) -> Iterator[RecentFileCacheRecord]:
44
46
  """Parse RecentFileCache.bcf.
45
47
 
46
48
  Yields RecentFileCacheRecords with fields:
@@ -1,3 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Iterator
4
+
1
5
  from dissect.target.exceptions import PluginError, UnsupportedPluginError
2
6
  from dissect.target.helpers.record import TargetRecordDescriptor
3
7
  from dissect.target.plugin import Plugin, export
@@ -37,7 +41,7 @@ class RegfPlugin(Plugin):
37
41
  raise UnsupportedPluginError("Registry plugin not loaded")
38
42
 
39
43
  @export(record=[RegistryKeyRecord, RegistryValueRecord])
40
- def regf(self):
44
+ def regf(self) -> Iterator[RegistryKeyRecord | RegistryValueRecord]:
41
45
  """Return all registry keys and values.
42
46
 
43
47
  The Windows Registry is a hierarchical database that stores low-level settings for the Windows operating system
@@ -108,7 +108,7 @@ MAGIC_WIN10 = 0x73743031
108
108
 
109
109
 
110
110
  class SHIMCACHE_WIN_TYPE(IntEnum):
111
- """Specific shimcache versions"""
111
+ """Shimcache version mapping."""
112
112
 
113
113
  VERSION_WIN10_CREATORS = 0x1001
114
114
  VERSION_WIN10 = 0x1000
@@ -54,7 +54,8 @@ class UsbPlugin(Plugin):
54
54
 
55
55
  To get a full picture of the USB history on a Windows machine, you should parse the
56
56
  relevant EventIDs using the evtx plugin. For more research on event log USB forensics, see:
57
- - https://www.researchgate.net/publication/318514858
57
+
58
+ - https://www.researchgate.net/publication/318514858_USB_Storage_Device_Forensics_for_Windows_10
58
59
  - https://dfir.pubpub.org/pub/h78di10n/release/2
59
60
  - https://www.senturean.com/posts/19_08_03_usb_storage_forensics_1/#1-system-events
60
61
 
@@ -1,4 +1,5 @@
1
1
  import codecs
2
+ from typing import Iterator
2
3
 
3
4
  from dissect.cstruct import cstruct
4
5
  from dissect.util.ts import wintimestamp
@@ -60,7 +61,7 @@ class UserAssistPlugin(Plugin):
60
61
  raise UnsupportedPluginError("No UserAssist key found")
61
62
 
62
63
  @export(record=UserAssistRecord)
63
- def userassist(self):
64
+ def userassist(self) -> Iterator[UserAssistRecord]:
64
65
  """Return the UserAssist information for each user.
65
66
 
66
67
  The UserAssist registry keys contain information about programs that were recently executed on the system.
@@ -68,6 +68,10 @@ class RegistryPlugin(Plugin):
68
68
  "COMPONENTS",
69
69
  "DEFAULT",
70
70
  "ELAM",
71
+ "USER.DAT", # Win 95/98/ME
72
+ "SYSTEM.DAT", # Win 95/98/ME
73
+ "CLASSES.DAT", # Win ME
74
+ "REG.DAT", # Win 3.1
71
75
  ]
72
76
 
73
77
  def __init__(self, target: Target) -> None:
@@ -88,7 +92,14 @@ class RegistryPlugin(Plugin):
88
92
 
89
93
  def _init_registry(self) -> None:
90
94
  dirs = [
95
+ # Windows XP or newer
91
96
  ("sysvol/windows/system32/config", False),
97
+ # Windows NT3, NT4, 2k
98
+ ("sysvol/WINNT/system32/config", False),
99
+ # Windows 3.11, 95, 98, ME
100
+ ("sysvol/windows", False),
101
+ # ReactOS (alternative location)
102
+ ("sysvol/reactos", False),
92
103
  # RegBack hives are often empty files
93
104
  ("sysvol/windows/system32/config/RegBack", True),
94
105
  ]
@@ -1,4 +1,5 @@
1
1
  import re
2
+ from typing import Iterator
2
3
 
3
4
  from dissect.target.exceptions import (
4
5
  RegistryError,
@@ -62,8 +63,8 @@ class ServicesPlugin(Plugin):
62
63
  raise UnsupportedPluginError("No services found in the registry")
63
64
 
64
65
  @export(record=ServiceRecord)
65
- def services(self):
66
- """Return information about all installed services.
66
+ def services(self) -> Iterator[ServiceRecord]:
67
+ """Return information about all installed Windows services.
67
68
 
68
69
  The HKLM\\SYSTEM\\CurrentControlSet\\Services registry key contains information about the installed services and
69
70
  drivers on the system.
@@ -1,4 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
4
+ from typing import Iterator
2
5
 
3
6
  from defusedxml import ElementTree
4
7
 
@@ -34,7 +37,7 @@ StartupInfoRecord = TargetRecordDescriptor(
34
37
  )
35
38
 
36
39
 
37
- def parse_ts(time_string):
40
+ def parse_ts(time_string: str) -> datetime.datetime | None:
38
41
  if not time_string:
39
42
  return None
40
43
 
@@ -42,6 +45,8 @@ def parse_ts(time_string):
42
45
 
43
46
 
44
47
  class StartupInfoPlugin(Plugin):
48
+ """Windows startup info plugin."""
49
+
45
50
  def __init__(self, target):
46
51
  super().__init__(target)
47
52
  self._files = []
@@ -55,7 +60,7 @@ class StartupInfoPlugin(Plugin):
55
60
  raise UnsupportedPluginError("No StartupInfo files found")
56
61
 
57
62
  @export(record=StartupInfoRecord)
58
- def startupinfo(self):
63
+ def startupinfo(self) -> Iterator[StartupInfoRecord]:
59
64
  """Return the contents of StartupInfo files.
60
65
 
61
66
  On a Windows system, the StartupInfo log files contain information about process execution for the first 90
@@ -1,3 +1,5 @@
1
+ from typing import Iterator
2
+
1
3
  from dissect.ntfs import ntfs
2
4
 
3
5
  from dissect.target.exceptions import RegistryValueNotFoundError, UnsupportedPluginError
@@ -41,7 +43,7 @@ class SyscachePlugin(Plugin):
41
43
  raise UnsupportedPluginError("Could not load Syscache.hve")
42
44
 
43
45
  @export(record=SyscacheRecord)
44
- def syscache(self):
46
+ def syscache(self) -> Iterator[SyscacheRecord]:
45
47
  """Parse the objects in the ObjectTable from the Syscache.hve file."""
46
48
 
47
49
  # Try to get the system volume
@@ -125,7 +125,7 @@ class TasksPlugin(Plugin):
125
125
  intervals. An adversary may leverage such scheduled tasks to gain persistence on a system.
126
126
 
127
127
  References:
128
- https://en.wikipedia.org/wiki/Windows_Task_Scheduler
128
+ - https://en.wikipedia.org/wiki/Windows_Task_Scheduler
129
129
 
130
130
  Yields:
131
131
  The scheduled tasks found on the target.
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from pathlib import Path
2
- from typing import Iterator, Optional, Union
4
+ from typing import Iterator
3
5
 
4
6
  from dissect.thumbcache import Error, Thumbcache
5
7
  from dissect.thumbcache.tools.extract_with_index import dump_entry_data_through_index
@@ -33,6 +35,8 @@ IconcacheRecord = TargetRecordDescriptor("windows/thumbcache/iconcache", GENERIC
33
35
 
34
36
 
35
37
  class ThumbcachePlugin(Plugin):
38
+ """Windows thumbcache plugin."""
39
+
36
40
  __namespace__ = "thumbcache"
37
41
 
38
42
  def get_cache_paths(self) -> Iterator[TargetPath]:
@@ -71,8 +75,8 @@ class ThumbcachePlugin(Plugin):
71
75
  self,
72
76
  record_type: TargetRecordDescriptor,
73
77
  prefix: str,
74
- output_dir: Optional[Path],
75
- ) -> Iterator[Union[ThumbcacheRecord, IconcacheRecord, IndexRecord]]:
78
+ output_dir: Path | None,
79
+ ) -> Iterator[ThumbcacheRecord | IconcacheRecord | IndexRecord]:
76
80
  for cache_path in self.get_cache_paths():
77
81
  try:
78
82
  if output_dir:
@@ -91,10 +95,12 @@ class ThumbcachePlugin(Plugin):
91
95
 
92
96
  @arg("--output", "-o", dest="output_dir", type=Path, help="Path to extract thumbcache thumbnails to.")
93
97
  @export(record=[ThumbcacheRecord, IndexRecord])
94
- def thumbcache(self, output_dir: Optional[Path] = None) -> Iterator[Union[ThumbcacheRecord, IndexRecord]]:
98
+ def thumbcache(self, output_dir: Path | None = None) -> Iterator[ThumbcacheRecord | IndexRecord]:
99
+ """Yield thumbcache thumbnails."""
95
100
  yield from self._parse_thumbcache(ThumbcacheRecord, "thumbcache", output_dir)
96
101
 
97
102
  @arg("--output", "-o", dest="output_dir", type=Path, help="Path to extract iconcache thumbnails to.")
98
103
  @export(record=[IconcacheRecord, IndexRecord])
99
- def iconcache(self, output_dir: Optional[Path] = None) -> Iterator[Union[IconcacheRecord, IndexRecord]]:
104
+ def iconcache(self, output_dir: Path | None = None) -> Iterator[IconcacheRecord | IndexRecord]:
105
+ """Yield iconcache thumbnails."""
100
106
  yield from self._parse_thumbcache(IconcacheRecord, "iconcache", output_dir)
@@ -1,3 +1,6 @@
1
+ from pathlib import Path
2
+ from typing import Any, Iterator
3
+
1
4
  from dissect.esedb.exceptions import Error
2
5
  from dissect.esedb.tools import ual
3
6
 
@@ -165,14 +168,14 @@ class UalPlugin(Plugin):
165
168
  if not any([path.exists() for path in self.mdb_paths]):
166
169
  raise UnsupportedPluginError("No MDB files found")
167
170
 
168
- def find_mdb_files(self):
171
+ def find_mdb_files(self) -> list[Path]:
169
172
  return [
170
173
  path
171
174
  for path in self.target.fs.path("/").glob(self.LOG_DB_GLOB)
172
175
  if path.exists() and path.name != self.IDENTITY_DB_FILENAME
173
176
  ]
174
177
 
175
- def populate_role_guid_map(self):
178
+ def populate_role_guid_map(self) -> None:
176
179
  identity_db = self.target.fs.path(self.IDENTITY_DB_PATH)
177
180
  if not identity_db.exists():
178
181
  return
@@ -192,13 +195,13 @@ class UalPlugin(Plugin):
192
195
  "role_name": record.get("RoleName"),
193
196
  }
194
197
 
195
- def read_table_records(self, table_name):
198
+ def read_table_records(self, table_name: str) -> Iterator[tuple[Path, dict[str, Any]]]:
196
199
  for mdb_path in self.mdb_paths:
197
200
  fh = mdb_path.open()
198
201
  try:
199
202
  parser = ual.UAL(fh)
200
203
  except Error as e:
201
- self.target.log.warning(f"Error opening {mdb_path} database", exc_info=e)
204
+ self.target.log.warning("Error opening database: %s", mdb_path, exc_info=e)
202
205
  continue
203
206
 
204
207
  for table_record in parser.get_table_records(table_name):
@@ -206,7 +209,7 @@ class UalPlugin(Plugin):
206
209
  yield mdb_path, values
207
210
 
208
211
  @export(record=ClientAccessRecord)
209
- def client_access(self):
212
+ def client_access(self) -> Iterator[ClientAccessRecord]:
210
213
  """Return client access data within the User Access Logs."""
211
214
  for path, client_record in self.read_table_records("CLIENTS"):
212
215
  common_values = {k: v for k, v in client_record.items() if k != "activity_counts"}
@@ -224,7 +227,7 @@ class UalPlugin(Plugin):
224
227
  )
225
228
 
226
229
  @export(record=RoleAccessRecord)
227
- def role_access(self):
230
+ def role_access(self) -> Iterator[RoleAccessRecord]:
228
231
  """Return role access data within the User Access Logs."""
229
232
  for path, record in self.read_table_records("ROLE_ACCESS"):
230
233
  role_guid_data = self.role_guid_map.get(record.get("role_guid"), {})
@@ -237,19 +240,19 @@ class UalPlugin(Plugin):
237
240
  )
238
241
 
239
242
  @export(record=VirtualMachineRecord)
240
- def virtual_machines(self):
243
+ def virtual_machines(self) -> Iterator[VirtualMachineRecord]:
241
244
  """Return virtual machine data within the User Access Logs."""
242
245
  for path, record in self.read_table_records("VIRTUALMACHINES"):
243
246
  yield VirtualMachineRecord(path=path, _target=self.target, **record)
244
247
 
245
248
  @export(record=DomainSeenRecord)
246
- def domains_seen(self):
249
+ def domains_seen(self) -> Iterator[DomainSeenRecord]:
247
250
  """Return DNS data within the User Access Logs."""
248
251
  for path, record in self.read_table_records("DNS"):
249
252
  yield DomainSeenRecord(path=path, _target=self.target, **record)
250
253
 
251
254
  @export(record=SystemIdentityRecord)
252
- def system_identities(self):
255
+ def system_identities(self) -> Iterator[SystemIdentityRecord]:
253
256
  """Return system identity data within the User Access Logs."""
254
257
  if not self.identity_db_parser:
255
258
  return
@@ -994,7 +994,6 @@ class WuaHistoryPlugin(Plugin):
994
994
  - https://learn.microsoft.com/en-us/windows/deployment/update/windows-update-error-reference
995
995
  - https://learn.microsoft.com/en-us/troubleshoot/windows-client/installing-updates-features-roles/common-windows-update-errors
996
996
  - https://learn.microsoft.com/en-us/troubleshoot/windows-client/installing-updates-features-roles/common-windows-update-errors?context=%2Fwindows%2Fdeployment%2Fcontext%2Fcontext
997
-
998
997
  - https://github.com/libyal/esedb-kb/blob/main/documentation/Windows%20Update.asciidoc
999
998
  - https://www.nirsoft.net/articles/extract-windows-updates-list-external-drive.html
1000
999
 
@@ -38,6 +38,8 @@ log = structlog.get_logger(__name__)
38
38
 
39
39
 
40
40
  class Compression(enum.Enum):
41
+ """Supported compression types."""
42
+
41
43
  BZIP2 = "bzip2"
42
44
  GZIP = "gzip"
43
45
  LZ4 = "lz4"
@@ -46,6 +48,8 @@ class Compression(enum.Enum):
46
48
 
47
49
 
48
50
  class Serialization(enum.Enum):
51
+ """Supported serialization methods."""
52
+
49
53
  JSONLINES = "jsonlines"
50
54
  MSGPACK = "msgpack"
51
55
 
@@ -205,7 +205,8 @@ class ExtendedCmd(cmd.Cmd):
205
205
 
206
206
  When entering an empty command, the cmd module will by default repeat the previous command.
207
207
  By defining an empty ``emptyline`` function we make sure no command is executed instead.
208
- Resources:
208
+
209
+ References:
209
210
  - https://stackoverflow.com/a/16479030
210
211
  - https://github.com/python/cpython/blob/3.12/Lib/cmd.py#L10
211
212
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.20.dev36
3
+ Version: 3.20.dev39
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