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,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from datetime import datetime
2
- from typing import Optional
4
+ from typing import Iterator
3
5
 
4
6
  from dissect.util.ts import from_unix
5
7
 
@@ -123,12 +125,12 @@ class GenericPlugin(Plugin):
123
125
  raise UnsupportedPluginError("Unsupported Plugin")
124
126
 
125
127
  @export(property=True)
126
- def ntversion(self):
128
+ def ntversion(self) -> str | None:
127
129
  """Return the Windows NT version."""
128
130
  return self.target._os._nt_version()
129
131
 
130
132
  @export(output="yield")
131
- def pathenvironment(self):
133
+ def pathenvironment(self) -> Iterator[str]:
132
134
  """Return the content of the Windows PATH environment variable.
133
135
 
134
136
  PATH is an environment variable on an operating system that specifies a set of directories where executable
@@ -142,7 +144,7 @@ class GenericPlugin(Plugin):
142
144
  yield r.value("Path").value
143
145
 
144
146
  @export(property=True)
145
- def domain(self):
147
+ def domain(self) -> str | None:
146
148
  """Return the domain name.
147
149
 
148
150
  Corporate Windows systems are usually connected to a domain (active directory).
@@ -167,7 +169,7 @@ class GenericPlugin(Plugin):
167
169
  continue
168
170
 
169
171
  @export(property=True)
170
- def activity(self) -> Optional[datetime]:
172
+ def activity(self) -> datetime | None:
171
173
  """Return last seen activity based on filesystem timestamps."""
172
174
  last_seen = 0
173
175
 
@@ -193,7 +195,7 @@ class GenericPlugin(Plugin):
193
195
  return from_unix(last_seen)
194
196
 
195
197
  @export(property=True)
196
- def install_date(self) -> Optional[datetime]:
198
+ def install_date(self) -> datetime | None:
197
199
  """Returns the install date of the system.
198
200
 
199
201
  The value of the registry key is stored as a Unix epoch timestamp.
@@ -211,7 +213,7 @@ class GenericPlugin(Plugin):
211
213
  return
212
214
 
213
215
  @export(record=AppInitRecord)
214
- def appinit(self):
216
+ def appinit(self) -> Iterator[AppInitRecord]:
215
217
  """Return all available Application Initial (AppInit) DLLs registry key values.
216
218
 
217
219
  AppInit_DLLs is a mechanism that allows an arbitrary list of DLLs to be loaded into each user mode process on
@@ -258,7 +260,7 @@ class GenericPlugin(Plugin):
258
260
  continue
259
261
 
260
262
  @export(record=KnownDllRecord)
261
- def knowndlls(self):
263
+ def knowndlls(self) -> Iterator[KnownDllRecord]:
262
264
  """Return all available KnownDLLs registry key values.
263
265
 
264
266
  The KnownDLLs registry key values are used to cache frequently used system DLLs. Initially, it was added to
@@ -287,7 +289,7 @@ class GenericPlugin(Plugin):
287
289
  pass
288
290
 
289
291
  @export(record=SessionManagerRecord)
290
- def sessionmanager(self):
292
+ def sessionmanager(self) -> Iterator[SessionManagerRecord]:
291
293
  """Return interesting Session Manager (Smss.exe) registry key entries.
292
294
 
293
295
  Session Manager (Smss.exe) is the first user-mode process started by the kernel and performs several tasks,
@@ -339,7 +341,7 @@ class GenericPlugin(Plugin):
339
341
  )
340
342
 
341
343
  @export(record=NullSessionPipeRecord)
342
- def nullsessionpipes(self):
344
+ def nullsessionpipes(self) -> Iterator[NullSessionPipeRecord]:
343
345
  """Return the NullSessionPipes registry key value.
344
346
 
345
347
  The NullSessionPipes registry key value specifies server pipes and shared folders that are excluded from the
@@ -367,7 +369,7 @@ class GenericPlugin(Plugin):
367
369
  continue
368
370
 
369
371
  @export(record=NdisRecord)
370
- def ndis(self):
372
+ def ndis(self) -> Iterator[NdisRecord]:
371
373
  """Return network registry key entries."""
372
374
  key = "HKLM\\System\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
373
375
  for r in self.target.registry.keys(key):
@@ -401,7 +403,7 @@ class GenericPlugin(Plugin):
401
403
  )
402
404
 
403
405
  @export(record=CommandProcAutoRunRecord)
404
- def commandprocautorun(self):
406
+ def commandprocautorun(self) -> Iterator[CommandProcAutoRunRecord]:
405
407
  """Return all available Command Processor (cmd.exe) AutoRun registry key values.
406
408
 
407
409
  The Command Processor AutoRun registry key values contain commands that are run each time the Command Processor
@@ -435,7 +437,7 @@ class GenericPlugin(Plugin):
435
437
  continue
436
438
 
437
439
  @export(record=AlternateShellRecord)
438
- def alternateshell(self):
440
+ def alternateshell(self) -> Iterator[AlternateShellRecord]:
439
441
  """Return the AlternateShell registry key value.
440
442
 
441
443
  The AlternateShell registry key, HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Safeboot, specifies the
@@ -459,7 +461,7 @@ class GenericPlugin(Plugin):
459
461
  )
460
462
 
461
463
  @export(record=BootShellRecord)
462
- def bootshell(self):
464
+ def bootshell(self) -> Iterator[BootShellRecord]:
463
465
  """Return the BootShell registry key entry.
464
466
 
465
467
  Usually contains a path to bootim.exe which is Windows's recovery menu.
@@ -483,7 +485,7 @@ class GenericPlugin(Plugin):
483
485
  )
484
486
 
485
487
  @export(record=FileRenameOperationRecord)
486
- def filerenameop(self):
488
+ def filerenameop(self) -> Iterator[FileRenameOperationRecord]:
487
489
  """Return all pending file rename operations.
488
490
 
489
491
  The PendingFileRenameOperations registry key value contains information about files that will be renamed on
@@ -513,7 +515,7 @@ class GenericPlugin(Plugin):
513
515
  )
514
516
 
515
517
  @export(record=WinRarRecord)
516
- def winrar(self):
518
+ def winrar(self) -> Iterator[WinRarRecord]:
517
519
  """Return all available WinRAR history registry key values."""
518
520
  keys = [
519
521
  "HKEY_CURRENT_USER\\Software\\WinRAR\\ArcHistory",
@@ -534,7 +536,7 @@ class GenericPlugin(Plugin):
534
536
  )
535
537
 
536
538
  @export(record=WinSockNamespaceProviderRecord)
537
- def winsocknamespaceprovider(self):
539
+ def winsocknamespaceprovider(self) -> Iterator[WinSockNamespaceProviderRecord]:
538
540
  """Return available protocols stored in the Winsock catalog database.
539
541
 
540
542
  References:
@@ -562,7 +564,7 @@ class GenericPlugin(Plugin):
562
564
  )
563
565
 
564
566
  @export(property=True)
565
- def codepage(self) -> Optional[str]:
567
+ def codepage(self) -> str | None:
566
568
  """Returns the current active codepage on the system."""
567
569
 
568
570
  key = "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage"
@@ -118,6 +118,8 @@ def parse_lnk_file(target: Target, lnk_file: Lnk, lnk_path: TargetPath) -> Itera
118
118
 
119
119
 
120
120
  class LnkPlugin(Plugin):
121
+ """Windows lnk plugin."""
122
+
121
123
  def __init__(self, target: Target) -> None:
122
124
  super().__init__(target)
123
125
  self.folders = ["programdata", "users", "windows"]
@@ -1,3 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Iterator
4
+
1
5
  from dissect.target.exceptions import UnsupportedPluginError
2
6
  from dissect.target.helpers.localeutil import normalize_language, normalize_timezone
3
7
  from dissect.target.helpers.record import TargetRecordDescriptor
@@ -13,6 +17,8 @@ WindowsKeyboardRecord = TargetRecordDescriptor(
13
17
 
14
18
 
15
19
  class LocalePlugin(Plugin):
20
+ """Windows locale plugin."""
21
+
16
22
  def __init__(self, target):
17
23
  super().__init__(target)
18
24
  self.LANG_DICT = {
@@ -26,7 +32,7 @@ class LocalePlugin(Plugin):
26
32
  raise UnsupportedPluginError("Unsupported Plugin")
27
33
 
28
34
  @export(record=WindowsKeyboardRecord)
29
- def keyboard(self):
35
+ def keyboard(self) -> Iterator[WindowsKeyboardRecord]:
30
36
  """Yield records of installed keyboards on the system."""
31
37
  found_keyboards = []
32
38
  for key in self.target.registry.keys("HKCU\\Keyboard Layout\\Preload"):
@@ -41,7 +47,7 @@ class LocalePlugin(Plugin):
41
47
  )
42
48
 
43
49
  @export(property=True)
44
- def language(self):
50
+ def language(self) -> str | None:
45
51
  """Get a list of installed languages on the system."""
46
52
  # HKCU\\Control Panel\\International\\User Profile" Languages
47
53
  found_languages = []
@@ -53,6 +59,6 @@ class LocalePlugin(Plugin):
53
59
  return found_languages
54
60
 
55
61
  @export(property=True)
56
- def timezone(self):
62
+ def timezone(self) -> str | None:
57
63
  """Get the configured timezone of the system in IANA TZ standard format."""
58
64
  return normalize_timezone(self.target.datetime.tzinfo.name)
@@ -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