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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) 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/shell/powershell.py +6 -2
  14. dissect/target/plugins/apps/shell/wget.py +1 -1
  15. dissect/target/plugins/apps/ssh/openssh.py +2 -0
  16. dissect/target/plugins/apps/ssh/opensshd.py +2 -0
  17. dissect/target/plugins/apps/vpn/wireguard.py +9 -9
  18. dissect/target/plugins/apps/webhosting/cpanel.py +2 -0
  19. dissect/target/plugins/apps/webserver/caddy.py +2 -0
  20. dissect/target/plugins/apps/webserver/nginx.py +2 -0
  21. dissect/target/plugins/child/esxi.py +3 -1
  22. dissect/target/plugins/child/virtuozzo.py +12 -8
  23. dissect/target/plugins/filesystem/acquire_hash.py +2 -1
  24. dissect/target/plugins/filesystem/icat.py +15 -11
  25. dissect/target/plugins/filesystem/ntfs/mft.py +2 -0
  26. dissect/target/plugins/filesystem/ntfs/mft_timeline.py +3 -1
  27. dissect/target/plugins/filesystem/ntfs/usnjrnl.py +2 -0
  28. dissect/target/plugins/filesystem/ntfs/utils.py +3 -1
  29. dissect/target/plugins/filesystem/unix/suid.py +4 -1
  30. dissect/target/plugins/filesystem/walkfs.py +2 -0
  31. dissect/target/plugins/general/example.py +2 -2
  32. dissect/target/plugins/general/loaders.py +1 -1
  33. dissect/target/plugins/general/network.py +7 -0
  34. dissect/target/plugins/general/osinfo.py +1 -0
  35. dissect/target/plugins/general/plugins.py +4 -0
  36. dissect/target/plugins/os/unix/_os.py +2 -1
  37. dissect/target/plugins/os/unix/bsd/citrix/history.py +2 -0
  38. dissect/target/plugins/os/unix/bsd/osx/network.py +2 -0
  39. dissect/target/plugins/os/unix/bsd/osx/user.py +4 -0
  40. dissect/target/plugins/os/unix/cronjobs.py +8 -4
  41. dissect/target/plugins/os/unix/etc/etc.py +4 -0
  42. dissect/target/plugins/os/unix/generic.py +2 -0
  43. dissect/target/plugins/os/unix/history.py +27 -25
  44. dissect/target/plugins/os/unix/linux/cmdline.py +2 -0
  45. dissect/target/plugins/os/unix/linux/debian/apt.py +4 -1
  46. dissect/target/plugins/os/unix/linux/debian/dpkg.py +3 -3
  47. dissect/target/plugins/os/unix/linux/environ.py +2 -0
  48. dissect/target/plugins/os/unix/linux/fortios/generic.py +2 -0
  49. dissect/target/plugins/os/unix/linux/fortios/locale.py +2 -0
  50. dissect/target/plugins/os/unix/linux/modules.py +2 -0
  51. dissect/target/plugins/os/unix/linux/netstat.py +2 -0
  52. dissect/target/plugins/os/unix/linux/processes.py +2 -0
  53. dissect/target/plugins/os/unix/linux/redhat/yum.py +4 -1
  54. dissect/target/plugins/os/unix/linux/services.py +5 -3
  55. dissect/target/plugins/os/unix/linux/sockets.py +2 -0
  56. dissect/target/plugins/os/unix/linux/suse/zypper.py +4 -1
  57. dissect/target/plugins/os/unix/locale.py +2 -0
  58. dissect/target/plugins/os/unix/locate/gnulocate.py +4 -2
  59. dissect/target/plugins/os/unix/locate/mlocate.py +2 -0
  60. dissect/target/plugins/os/unix/locate/plocate.py +3 -1
  61. dissect/target/plugins/os/unix/log/atop.py +2 -0
  62. dissect/target/plugins/os/unix/log/audit.py +3 -1
  63. dissect/target/plugins/os/unix/log/auth.py +4 -2
  64. dissect/target/plugins/os/unix/log/lastlog.py +5 -3
  65. dissect/target/plugins/os/unix/log/messages.py +2 -0
  66. dissect/target/plugins/os/unix/log/utmp.py +4 -2
  67. dissect/target/plugins/os/unix/packagemanager.py +4 -37
  68. dissect/target/plugins/os/unix/shadow.py +3 -1
  69. dissect/target/plugins/os/unix/trash.py +1 -1
  70. dissect/target/plugins/os/windows/activitiescache.py +9 -4
  71. dissect/target/plugins/os/windows/adpolicy.py +2 -1
  72. dissect/target/plugins/os/windows/amcache.py +16 -13
  73. dissect/target/plugins/os/windows/defender.py +3 -3
  74. dissect/target/plugins/os/windows/dpapi/keyprovider/credhist.py +3 -0
  75. dissect/target/plugins/os/windows/dpapi/keyprovider/empty.py +3 -0
  76. dissect/target/plugins/os/windows/dpapi/keyprovider/keychain.py +3 -0
  77. dissect/target/plugins/os/windows/dpapi/keyprovider/lsa.py +3 -0
  78. dissect/target/plugins/os/windows/env.py +1 -2
  79. dissect/target/plugins/os/windows/exchange/exchange.py +6 -4
  80. dissect/target/plugins/os/windows/generic.py +20 -18
  81. dissect/target/plugins/os/windows/lnk.py +2 -0
  82. dissect/target/plugins/os/windows/locale.py +9 -3
  83. dissect/target/plugins/os/windows/log/etl.py +5 -4
  84. dissect/target/plugins/os/windows/log/evt.py +12 -8
  85. dissect/target/plugins/os/windows/log/evtx.py +9 -7
  86. dissect/target/plugins/os/windows/log/pfro.py +2 -1
  87. dissect/target/plugins/os/windows/network.py +2 -0
  88. dissect/target/plugins/os/windows/notifications.py +6 -4
  89. dissect/target/plugins/os/windows/prefetch.py +7 -2
  90. dissect/target/plugins/os/windows/regf/7zip.py +9 -1
  91. dissect/target/plugins/os/windows/regf/auditpol.py +2 -1
  92. dissect/target/plugins/os/windows/regf/bam.py +3 -1
  93. dissect/target/plugins/os/windows/regf/cit.py +14 -12
  94. dissect/target/plugins/os/windows/regf/clsid.py +6 -3
  95. dissect/target/plugins/os/windows/regf/firewall.py +2 -1
  96. dissect/target/plugins/os/windows/regf/mru.py +9 -8
  97. dissect/target/plugins/os/windows/regf/nethist.py +6 -3
  98. dissect/target/plugins/os/windows/regf/recentfilecache.py +3 -1
  99. dissect/target/plugins/os/windows/regf/regf.py +5 -1
  100. dissect/target/plugins/os/windows/regf/shimcache.py +1 -1
  101. dissect/target/plugins/os/windows/regf/usb.py +2 -1
  102. dissect/target/plugins/os/windows/regf/userassist.py +2 -1
  103. dissect/target/plugins/os/windows/registry.py +11 -0
  104. dissect/target/plugins/os/windows/services.py +3 -2
  105. dissect/target/plugins/os/windows/startupinfo.py +7 -2
  106. dissect/target/plugins/os/windows/syscache.py +3 -1
  107. dissect/target/plugins/os/windows/tasks.py +1 -1
  108. dissect/target/plugins/os/windows/thumbcache.py +11 -5
  109. dissect/target/plugins/os/windows/ual.py +12 -9
  110. dissect/target/plugins/os/windows/wua_history.py +0 -1
  111. dissect/target/tools/dump/utils.py +4 -0
  112. dissect/target/tools/shell.py +2 -1
  113. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev38.dist-info}/METADATA +1 -1
  114. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev38.dist-info}/RECORD +119 -120
  115. dissect/target/plugins/os/unix/etc.py +0 -9
  116. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev38.dist-info}/COPYRIGHT +0 -0
  117. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev38.dist-info}/LICENSE +0 -0
  118. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev38.dist-info}/WHEEL +0 -0
  119. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev38.dist-info}/entry_points.txt +0 -0
  120. {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev38.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  from functools import lru_cache
2
2
  from pathlib import Path
3
+ from typing import Iterator
3
4
 
4
5
  from dissect.etl.etl import ETL, Event
5
6
 
@@ -65,7 +66,7 @@ class EtlRecordBuilder:
65
66
 
66
67
 
67
68
  class EtlPlugin(Plugin):
68
- """Plugin for fetching and parsing Windows ETL Files (*.etl)"""
69
+ """Plugin for parsing Windows ETL Files (``*.etl``)."""
69
70
 
70
71
  __namespace__ = "etl"
71
72
 
@@ -108,7 +109,7 @@ class EtlPlugin(Plugin):
108
109
  yield from etl_records
109
110
 
110
111
  @export(record=DynamicDescriptor(["datetime"]))
111
- def etl(self):
112
+ def etl(self) -> Iterator[DynamicDescriptor]:
112
113
  """Return the contents of the ETL files generated at last boot and last shutdown.
113
114
 
114
115
  An event trace log (.etl) file, also known as a trace log, stores the trace messages generated during one or
@@ -135,7 +136,7 @@ class EtlPlugin(Plugin):
135
136
  yield from getattr(self, etl_plugin)()
136
137
 
137
138
  @export(record=DynamicDescriptor(["datetime"]))
138
- def shutdown(self):
139
+ def shutdown(self) -> Iterator[DynamicDescriptor]:
139
140
  """Return the contents of the ETL files created at last shutdown.
140
141
 
141
142
  The plugin reads the content from the ShutdownCKCL.etl file or the ShutdownPerfDiagLogger.etl file (depending
@@ -155,7 +156,7 @@ class EtlPlugin(Plugin):
155
156
  yield from self.read_etl_files(self.PATHS["shutdown"])
156
157
 
157
158
  @export(record=DynamicDescriptor(["datetime"]))
158
- def boot(self):
159
+ def boot(self) -> Iterator[DynamicDescriptor]:
159
160
  """Return the contents of the ETL files created at last boot.
160
161
 
161
162
  The plugin reads the content from the BootCKCL.etl file or the BootPerfDiagLogger.etl file (depending
@@ -1,7 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import fnmatch
2
4
  import re
3
5
  from pathlib import Path
4
- from typing import Any, BinaryIO, Generator, List, Optional
6
+ from typing import Any, BinaryIO, Iterator
5
7
 
6
8
  from dissect.eventlog import evt
7
9
  from flow.record import Record
@@ -48,7 +50,7 @@ class WindowsEventlogsMixin:
48
50
  LOGS_DIR_PATH = None
49
51
 
50
52
  @plugin.internal
51
- def get_logs(self, filename_glob="*") -> List[Path]:
53
+ def get_logs(self, filename_glob="*") -> list[Path]:
52
54
  file_paths = []
53
55
  file_paths.extend(self.get_logs_from_dir(self.LOGS_DIR_PATH, filename_glob=filename_glob))
54
56
 
@@ -66,7 +68,7 @@ class WindowsEventlogsMixin:
66
68
  return file_paths
67
69
 
68
70
  @plugin.internal
69
- def get_logs_from_dir(self, logs_dir: str, filename_glob: str = "*") -> List[Path]:
71
+ def get_logs_from_dir(self, logs_dir: str, filename_glob: str = "*") -> list[Path]:
70
72
  file_paths = []
71
73
  logs_dir = self.target.fs.path(logs_dir)
72
74
  if logs_dir.exists():
@@ -76,7 +78,7 @@ class WindowsEventlogsMixin:
76
78
  return file_paths
77
79
 
78
80
  @plugin.internal
79
- def get_logs_from_registry(self, filename_glob: str = "*") -> List[Path]:
81
+ def get_logs_from_registry(self, filename_glob: str = "*") -> list[Path]:
80
82
  # compile glob into case-insensitive regex
81
83
  filename_regex = re.compile(fnmatch.translate(filename_glob), re.IGNORECASE)
82
84
 
@@ -112,6 +114,8 @@ class WindowsEventlogsMixin:
112
114
 
113
115
 
114
116
  class EvtPlugin(WindowsEventlogsMixin, plugin.Plugin):
117
+ """Windows ``.evt`` event log plugin."""
118
+
115
119
  LOGS_DIR_PATH = "sysvol/windows/system32/config"
116
120
 
117
121
  NEEDLE = b"LfLe"
@@ -120,8 +124,8 @@ class EvtPlugin(WindowsEventlogsMixin, plugin.Plugin):
120
124
  @plugin.arg("--logs-dir", help="logs directory to scan")
121
125
  @plugin.arg("--log-file-glob", default=EVT_GLOB, help="glob pattern to match a log file name")
122
126
  @plugin.export(record=EvtRecordDescriptor)
123
- def evt(self, log_file_glob: str = EVT_GLOB, logs_dir: Optional[str] = None) -> Generator[Record, None, None]:
124
- """Parse Windows Eventlog files (*.evt).
127
+ def evt(self, log_file_glob: str = EVT_GLOB, logs_dir: str | None = None) -> Iterator[EvtRecordDescriptor]:
128
+ """Parse Windows Eventlog files (``*.evt``).
125
129
 
126
130
  Yields dynamically created records based on the fields in the event.
127
131
  At least contains the following fields:
@@ -174,7 +178,7 @@ class EvtPlugin(WindowsEventlogsMixin, plugin.Plugin):
174
178
  )
175
179
 
176
180
  @plugin.export(record=EvtRecordDescriptor)
177
- def scraped_evt(self) -> Generator[Record, None, None]:
181
+ def scraped_evt(self) -> Iterator[EvtRecordDescriptor]:
178
182
  """Yields EVT log file records scraped from target disks"""
179
183
  yield from self.target.scrape.scrape_chunks_from_disks(
180
184
  needle=self.NEEDLE,
@@ -189,6 +193,6 @@ class EvtPlugin(WindowsEventlogsMixin, plugin.Plugin):
189
193
  fh.seek(offset - 4)
190
194
  return fh.read(chunk_size)
191
195
 
192
- def _parse_chunk(self, _, chunk: bytes) -> Generator[Record, None, None]:
196
+ def _parse_chunk(self, _, chunk: bytes) -> Iterator[Record]:
193
197
  for record in evt.parse_chunk(chunk):
194
198
  yield self._build_record(record)
@@ -1,7 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
4
  import re
3
5
  from functools import lru_cache
4
- from typing import Any, Generator, Optional
6
+ from typing import Any, Iterator
5
7
 
6
8
  from dissect.eventlog import evtx
7
9
  from dissect.eventlog.exceptions import MalformedElfChnkException
@@ -19,7 +21,7 @@ EVTX_GLOB = "*.evtx"
19
21
 
20
22
 
21
23
  class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
22
- """Plugin for fetching and parsing Windows Eventlog Files (*.evtx)"""
24
+ """Plugin for fetching and parsing Windows Eventlog Files (``*.evtx``)."""
23
25
 
24
26
  RECORD_NAME = "filesystem/windows/evtx"
25
27
  LOGS_DIR_PATH = "sysvol/windows/system32/winevt/logs"
@@ -34,11 +36,11 @@ class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
34
36
  @plugin.arg("--logs-dir", help="logs directory to scan")
35
37
  @plugin.arg("--log-file-glob", default=EVTX_GLOB, help="glob pattern to match a log file name")
36
38
  @plugin.export(record=DynamicDescriptor(["datetime"]))
37
- def evtx(self, log_file_glob: str = EVTX_GLOB, logs_dir: Optional[str] = None) -> Generator[Record, None, None]:
38
- """Return entries from Windows Event log files (*.evtx).
39
+ def evtx(self, log_file_glob: str = EVTX_GLOB, logs_dir: str | None = None) -> Iterator[DynamicDescriptor]:
40
+ """Return entries from Windows Event log files (``*.evtx``).
39
41
 
40
42
  Windows Event log is a detailed record of system, security and application notifications. It can be used to
41
- diagnose a system or find future issues. Up until Windows XP the extension .evt was used, hereafter .evtx
43
+ diagnose a system or find future issues. Up until Windows XP the extension .evt was used, hereafter ``.evtx``
42
44
  became the new standard.
43
45
 
44
46
  References:
@@ -77,7 +79,7 @@ class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
77
79
  yield self._build_record(event)
78
80
 
79
81
  @plugin.export(record=DynamicDescriptor(["datetime"]))
80
- def scraped_evtx(self) -> Generator[Record, None, None]:
82
+ def scraped_evtx(self) -> Iterator[DynamicDescriptor]:
81
83
  """Return EVTX log file records scraped from target disks"""
82
84
  yield from self.target.scrape.scrape_chunks_from_disks(
83
85
  needle=self.NEEDLE,
@@ -85,7 +87,7 @@ class EvtxPlugin(WindowsEventlogsMixin, plugin.Plugin):
85
87
  chunk_parser=self._parse_chunk,
86
88
  )
87
89
 
88
- def _parse_chunk(self, _, chunk: bytes) -> Generator[Any, None, None]:
90
+ def _parse_chunk(self, _, chunk: bytes) -> Iterator[Record]:
89
91
  chnk = evtx.ElfChnk(chunk)
90
92
  try:
91
93
  for event in chnk.read():
@@ -1,5 +1,6 @@
1
1
  import datetime
2
2
  import re
3
+ from typing import Iterator
3
4
 
4
5
  from dissect.target.exceptions import UnsupportedPluginError
5
6
  from dissect.target.helpers.record import TargetRecordDescriptor
@@ -29,7 +30,7 @@ class PfroPlugin(Plugin):
29
30
  raise UnsupportedPluginError("No PFRO log found")
30
31
 
31
32
  @export(record=PfroRecord)
32
- def pfro(self):
33
+ def pfro(self) -> Iterator[PfroRecord]:
33
34
  """Return the content of sysvol/Windows/PFRO.log
34
35
 
35
36
  A Pending File Rename Operation log file (PFRO.log) holds information about the process of deleting or renaming
@@ -223,6 +223,8 @@ def _try_value(subkey: RegistryKey, value: str) -> str | list | None:
223
223
 
224
224
 
225
225
  class WindowsNetworkPlugin(NetworkPlugin):
226
+ """Windows network interface plugin."""
227
+
226
228
  def _interfaces(self) -> Iterator[WindowsInterfaceRecord]:
227
229
  # Get all the network interfaces
228
230
  for keys in self.target.registry.keys(
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
- from typing import Iterator, Optional
4
+ from typing import Iterator
3
5
  from uuid import UUID
4
6
 
5
7
  from dissect.cstruct import cstruct
@@ -253,7 +255,7 @@ class NotificationsPlugin(Plugin):
253
255
  chunk: c_appdb.Chunk,
254
256
  chunk_num: int,
255
257
  user: WindowsUserRecord,
256
- ) -> Optional[AppDBPushRecord]:
258
+ ) -> AppDBPushRecord | None:
257
259
  badge_record = None
258
260
  push_uri = chunk.Push.Uri.split(b"\x00")[0]
259
261
  push_uri = push_uri.decode("utf-8", errors="surrogateescape")
@@ -282,7 +284,7 @@ class NotificationsPlugin(Plugin):
282
284
  chunk: c_appdb.Chunk,
283
285
  chunk_num: int,
284
286
  user: WindowsUserRecord,
285
- ) -> Optional[AppDBBadgeRecord]:
287
+ ) -> AppDBBadgeRecord | None:
286
288
  badge_record = None
287
289
  badge_id = chunk.Badge.Id
288
290
 
@@ -432,7 +434,7 @@ class NotificationsPlugin(Plugin):
432
434
  yield toast_record
433
435
 
434
436
  @export(record=[WpnDatabaseNotificationRecord, WpnDatabaseNotificationHandlerRecord])
435
- def wpndatabase(self):
437
+ def wpndatabase(self) -> Iterator[WpnDatabaseNotificationRecord | WpnDatabaseNotificationHandlerRecord]:
436
438
  """Returns Windows Notifications from wpndatabase.db (post Windows 10 Anniversary).
437
439
 
438
440
  References:
@@ -1,4 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from io import BytesIO
4
+ from typing import Iterator
2
5
 
3
6
  from dissect.cstruct import cstruct
4
7
  from dissect.util import lzxpress_huffman
@@ -237,6 +240,8 @@ class Prefetch:
237
240
 
238
241
 
239
242
  class PrefetchPlugin(Plugin):
243
+ """Windows prefetch plugin."""
244
+
240
245
  def __init__(self, target):
241
246
  super().__init__(target)
242
247
  self.prefetchdir = self.target.fs.path("sysvol/windows/prefetch")
@@ -247,7 +252,7 @@ class PrefetchPlugin(Plugin):
247
252
 
248
253
  @export(record=[PrefetchRecord, GroupedPrefetchRecord])
249
254
  @arg("--grouped", action="store_true", help="Group the prefetch record")
250
- def prefetch(self, grouped=False):
255
+ def prefetch(self, grouped=False) -> Iterator[PrefetchRecord | GroupedPrefetchRecord]:
251
256
  """Return the content of all prefetch files.
252
257
 
253
258
  Prefetch is a memory management feature in Windows. It contains information (for example run count and
@@ -268,7 +273,7 @@ class PrefetchPlugin(Plugin):
268
273
  linkedfile (path): The linked file entry.
269
274
  runcount (int): The run count.
270
275
 
271
- with --grouped:
276
+ with ``--grouped``:
272
277
 
273
278
  Yields PrefetchRecords with fields:
274
279
 
@@ -1,3 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Iterator
4
+
1
5
  from dissect.target.exceptions import RegistryError, UnsupportedPluginError
2
6
  from dissect.target.helpers.record import TargetRecordDescriptor
3
7
  from dissect.target.plugin import Plugin, export
@@ -48,6 +52,8 @@ FolderHistoryRecord = TargetRecordDescriptor(
48
52
 
49
53
 
50
54
  class SevenZipPlugin(Plugin):
55
+ """Windows 7-Zip GUI plugin."""
56
+
51
57
  KEY = "HKCU\\Software\\7-Zip"
52
58
 
53
59
  def check_compatible(self) -> None:
@@ -71,7 +77,9 @@ class SevenZipPlugin(Plugin):
71
77
  pass
72
78
 
73
79
  @export(record=[PanelPathRecord, ArcHistoryRecord, PathHistoryRecord, CopyHistoryRecord, FolderHistoryRecord])
74
- def sevenzip(self):
80
+ def sevenzip(
81
+ self,
82
+ ) -> Iterator[PanelPathRecord | ArcHistoryRecord | PathHistoryRecord | CopyHistoryRecord | FolderHistoryRecord]:
75
83
  """Return 7-Zip history information from the registry.
76
84
 
77
85
  7-Zip is an open source file archiver. If the HKCU\\Software\\7-Zip registry key exists, it checks for
@@ -1,4 +1,5 @@
1
1
  import io
2
+ from typing import Iterator
2
3
 
3
4
  from dissect.cstruct import cstruct
4
5
 
@@ -138,7 +139,7 @@ class AuditpolPlugin(Plugin):
138
139
  raise UnsupportedPluginError(f"Registry key {self.KEY} not found")
139
140
 
140
141
  @export(record=AuditPolicyRecord)
141
- def auditpol(self):
142
+ def auditpol(self) -> Iterator[AuditPolicyRecord]:
142
143
  """Return audit policy settings from the registry.
143
144
 
144
145
  For Windows, the audit policy settings are stored in the HKEY_LOCAL_MACHINE\\Security\\Policy\\PolAdtEv registry
@@ -1,3 +1,5 @@
1
+ from typing import Iterator
2
+
1
3
  from dissect.cstruct import cstruct
2
4
  from dissect.util.ts import wintimestamp
3
5
 
@@ -36,7 +38,7 @@ class BamDamPlugin(Plugin):
36
38
  raise UnsupportedPluginError("No bam or dam registry keys not found")
37
39
 
38
40
  @export(record=BamDamRecord)
39
- def bam(self):
41
+ def bam(self) -> Iterator[BamDamRecord]:
40
42
  """Parse bam and dam registry keys.
41
43
 
42
44
  Yields BamDamRecords with fields:
@@ -1,12 +1,10 @@
1
- # Resources:
2
- # - generaltel.dll
3
- # - win32k.sys (Windows 7)
4
- # - win32kbase.sys (Windows 10)
1
+ from __future__ import annotations
5
2
 
6
3
  import datetime
7
4
  import struct
8
5
  from binascii import crc32
9
6
  from io import BytesIO
7
+ from typing import Iterator, Union, get_args
10
8
 
11
9
  from dissect.cstruct import cstruct
12
10
  from dissect.util.compression import lznt1
@@ -20,6 +18,10 @@ from dissect.target.helpers.record import (
20
18
  )
21
19
  from dissect.target.plugin import Plugin, export
22
20
 
21
+ # Resources:
22
+ # - generaltel.dll
23
+ # - win32k.sys (Windows 7)
24
+ # - win32kbase.sys (Windows 10)
23
25
  cit_def = """
24
26
  typedef QWORD FILETIME;
25
27
 
@@ -353,7 +355,7 @@ CITProgramBitmapForegroundRecord = TargetRecordDescriptor(
353
355
  )
354
356
 
355
357
 
356
- CIT_RECORDS = [
358
+ CITRecords = Union[
357
359
  CITSystemRecord,
358
360
  CITSystemBitmapDisplayPowerRecord,
359
361
  CITSystemBitmapDisplayRequestChangeRecord,
@@ -602,7 +604,7 @@ class ProgramDataBitmaps(BaseUseDataBitmaps):
602
604
  self.foreground = self._parse_bitmap(0)
603
605
 
604
606
 
605
- def decode_name(name):
607
+ def decode_name(name: str) -> bytes:
606
608
  """Decode the registry key name.
607
609
 
608
610
  The CIT key name in the registry has some strange encoding.
@@ -642,8 +644,8 @@ class CITPlugin(Plugin):
642
644
  if not len(list(self.target.registry.keys(self.KEY))) > 0:
643
645
  raise UnsupportedPluginError("No CIT registry key found")
644
646
 
645
- @export(record=CIT_RECORDS)
646
- def cit(self):
647
+ @export(record=get_args(CITRecords))
648
+ def cit(self) -> Iterator[CITRecords]:
647
649
  """Return CIT data from the registry for executed executable information.
648
650
 
649
651
  CIT data is stored at HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\CIT\\System.
@@ -772,7 +774,7 @@ class CITPlugin(Plugin):
772
774
  self.target.log.exception("Failed to parse CIT value: %s", value.name)
773
775
 
774
776
  @export(record=CITPostUpdateUseInfoRecord)
775
- def puu(self):
777
+ def puu(self) -> Iterator[CITPostUpdateUseInfoRecord]:
776
778
  """Parse CIT PUU (Post Update Usage) data from the registry.
777
779
 
778
780
  Generally only available since Windows 10.
@@ -823,7 +825,7 @@ class CITPlugin(Plugin):
823
825
  )
824
826
 
825
827
  @export(record=[CITDPRecord, CITDPDurationRecord])
826
- def dp(self):
828
+ def dp(self) -> Iterator[CITDPRecord | CITDPDurationRecord]:
827
829
  """Parse CIT DP data from the registry.
828
830
 
829
831
  Generally only available since Windows 10.
@@ -878,7 +880,7 @@ class CITPlugin(Plugin):
878
880
  )
879
881
 
880
882
  @export(record=CITTelemetryRecord)
881
- def telemetry(self):
883
+ def telemetry(self) -> Iterator[CITTelemetryRecord]:
882
884
  """Parse CIT process telemetry answers from the registry.
883
885
 
884
886
  In some versions of Windows, processes would get "telemetry answers" set on their process struct, based on
@@ -899,7 +901,7 @@ class CITPlugin(Plugin):
899
901
  )
900
902
 
901
903
  @export(record=CITModuleRecord)
902
- def modules(self):
904
+ def modules(self) -> Iterator[CITModuleRecord]:
903
905
  """Parse CIT tracked module information from the registry.
904
906
 
905
907
  Contains applications that loaded a tracked module. By default these are:
@@ -1,9 +1,12 @@
1
+ from typing import Iterator
2
+
1
3
  from dissect.target.exceptions import RegistryError, UnsupportedPluginError
2
4
  from dissect.target.helpers.descriptor_extensions import (
3
5
  RegistryRecordDescriptorExtension,
4
6
  UserRecordDescriptorExtension,
5
7
  )
6
8
  from dissect.target.helpers.record import create_extended_descriptor
9
+ from dissect.target.helpers.regutil import RegistryKey
7
10
  from dissect.target.plugin import Plugin, export
8
11
 
9
12
  CLSIDRecordDescriptor = create_extended_descriptor(
@@ -50,7 +53,7 @@ class CLSIDPlugin(Plugin):
50
53
  if not len(list(self.target.registry.keys(list(self.KEYS.values())))) > 0:
51
54
  raise UnsupportedPluginError("No CLSID key found")
52
55
 
53
- def create_records(self, keys):
56
+ def create_records(self, keys: list[RegistryKey]) -> Iterator[CLSIDRecord]:
54
57
  """Iterate all CLSID keys from HKEY_CURRENT_USER\\Software\\Classes\\CLSID and
55
58
  HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID.
56
59
 
@@ -98,11 +101,11 @@ class CLSIDPlugin(Plugin):
98
101
  )
99
102
 
100
103
  @export(record=CLSIDRecord)
101
- def user(self):
104
+ def user(self) -> Iterator[CLSIDRecord]:
102
105
  """Return only the user CLSID registry keys."""
103
106
  yield from self.create_records(self.KEYS["user"])
104
107
 
105
108
  @export(record=CLSIDRecord)
106
- def machine(self):
109
+ def machine(self) -> Iterator[CLSIDRecord]:
107
110
  """Return only the machine CLSID registry keys."""
108
111
  yield from self.create_records(self.KEYS["machine"])
@@ -1,4 +1,5 @@
1
1
  import re
2
+ from typing import Iterator
2
3
 
3
4
  from dissect.target.exceptions import UnsupportedPluginError
4
5
  from dissect.target.helpers.record import DynamicDescriptor, TargetRecordDescriptor
@@ -19,7 +20,7 @@ class FirewallPlugin(Plugin):
19
20
  raise UnsupportedPluginError(f"Registry key {self.KEY} not found")
20
21
 
21
22
  @export(record=DynamicDescriptor(["uri"]))
22
- def firewall(self):
23
+ def firewall(self) -> Iterator[DynamicDescriptor]:
23
24
  """Return firewall rules saved in the registry.
24
25
 
25
26
  For a Windows operating system, the Firewall rules are stored in the
@@ -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.