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.
- dissect/target/filesystems/config.py +1 -1
- dissect/target/helpers/compat/path_common.py +5 -5
- dissect/target/helpers/configutil.py +31 -29
- dissect/target/helpers/cyber.py +2 -0
- dissect/target/helpers/docs.py +1 -1
- dissect/target/helpers/keychain.py +2 -0
- dissect/target/helpers/mount.py +2 -1
- dissect/target/plugin.py +15 -13
- dissect/target/plugins/apps/av/mcafee.py +2 -0
- dissect/target/plugins/apps/av/sophos.py +2 -0
- dissect/target/plugins/apps/av/trendmicro.py +2 -0
- dissect/target/plugins/apps/browser/chromium.py +27 -6
- dissect/target/plugins/apps/editor/editor.py +23 -0
- dissect/target/plugins/apps/{texteditor → editor}/windowsnotepad.py +40 -31
- dissect/target/plugins/apps/shell/powershell.py +6 -2
- dissect/target/plugins/apps/shell/wget.py +1 -1
- dissect/target/plugins/apps/ssh/openssh.py +2 -0
- dissect/target/plugins/apps/ssh/opensshd.py +2 -0
- dissect/target/plugins/apps/vpn/wireguard.py +9 -9
- dissect/target/plugins/apps/webhosting/cpanel.py +2 -0
- dissect/target/plugins/apps/webserver/caddy.py +2 -0
- dissect/target/plugins/apps/webserver/nginx.py +2 -0
- dissect/target/plugins/child/esxi.py +3 -1
- dissect/target/plugins/child/virtuozzo.py +12 -8
- dissect/target/plugins/filesystem/acquire_hash.py +2 -1
- dissect/target/plugins/filesystem/icat.py +15 -11
- dissect/target/plugins/filesystem/ntfs/mft.py +2 -0
- dissect/target/plugins/filesystem/ntfs/mft_timeline.py +3 -1
- dissect/target/plugins/filesystem/ntfs/usnjrnl.py +2 -0
- dissect/target/plugins/filesystem/ntfs/utils.py +3 -1
- dissect/target/plugins/filesystem/unix/suid.py +4 -1
- dissect/target/plugins/filesystem/walkfs.py +2 -0
- dissect/target/plugins/general/example.py +2 -2
- dissect/target/plugins/general/loaders.py +1 -1
- dissect/target/plugins/general/network.py +7 -0
- dissect/target/plugins/general/osinfo.py +1 -0
- dissect/target/plugins/general/plugins.py +4 -0
- dissect/target/plugins/os/unix/_os.py +2 -1
- dissect/target/plugins/os/unix/bsd/citrix/history.py +2 -0
- dissect/target/plugins/os/unix/bsd/osx/network.py +2 -0
- dissect/target/plugins/os/unix/bsd/osx/user.py +4 -0
- dissect/target/plugins/os/unix/cronjobs.py +8 -4
- dissect/target/plugins/os/unix/etc/etc.py +4 -0
- dissect/target/plugins/os/unix/generic.py +2 -0
- dissect/target/plugins/os/unix/history.py +27 -25
- dissect/target/plugins/os/unix/linux/cmdline.py +2 -0
- dissect/target/plugins/os/unix/linux/debian/apt.py +4 -1
- dissect/target/plugins/os/unix/linux/debian/dpkg.py +3 -3
- dissect/target/plugins/os/unix/linux/environ.py +2 -0
- dissect/target/plugins/os/unix/linux/fortios/generic.py +2 -0
- dissect/target/plugins/os/unix/linux/fortios/locale.py +2 -0
- dissect/target/plugins/os/unix/linux/modules.py +2 -0
- dissect/target/plugins/os/unix/linux/netstat.py +2 -0
- dissect/target/plugins/os/unix/linux/processes.py +2 -0
- dissect/target/plugins/os/unix/linux/redhat/yum.py +4 -1
- dissect/target/plugins/os/unix/linux/services.py +5 -3
- dissect/target/plugins/os/unix/linux/sockets.py +2 -0
- dissect/target/plugins/os/unix/linux/suse/zypper.py +4 -1
- dissect/target/plugins/os/unix/locale.py +2 -0
- dissect/target/plugins/os/unix/locate/gnulocate.py +4 -2
- dissect/target/plugins/os/unix/locate/mlocate.py +2 -0
- dissect/target/plugins/os/unix/locate/plocate.py +3 -1
- dissect/target/plugins/os/unix/log/atop.py +2 -0
- dissect/target/plugins/os/unix/log/audit.py +3 -1
- dissect/target/plugins/os/unix/log/auth.py +4 -2
- dissect/target/plugins/os/unix/log/lastlog.py +5 -3
- dissect/target/plugins/os/unix/log/messages.py +2 -0
- dissect/target/plugins/os/unix/log/utmp.py +4 -2
- dissect/target/plugins/os/unix/packagemanager.py +4 -37
- dissect/target/plugins/os/unix/shadow.py +3 -1
- dissect/target/plugins/os/unix/trash.py +1 -1
- dissect/target/plugins/os/windows/activitiescache.py +9 -4
- dissect/target/plugins/os/windows/adpolicy.py +2 -1
- dissect/target/plugins/os/windows/amcache.py +16 -13
- dissect/target/plugins/os/windows/defender.py +3 -3
- dissect/target/plugins/os/windows/dpapi/keyprovider/credhist.py +3 -0
- dissect/target/plugins/os/windows/dpapi/keyprovider/empty.py +3 -0
- dissect/target/plugins/os/windows/dpapi/keyprovider/keychain.py +3 -0
- dissect/target/plugins/os/windows/dpapi/keyprovider/lsa.py +3 -0
- dissect/target/plugins/os/windows/env.py +1 -2
- dissect/target/plugins/os/windows/exchange/exchange.py +6 -4
- dissect/target/plugins/os/windows/generic.py +20 -18
- dissect/target/plugins/os/windows/lnk.py +2 -0
- dissect/target/plugins/os/windows/locale.py +9 -3
- dissect/target/plugins/os/windows/log/etl.py +5 -4
- dissect/target/plugins/os/windows/log/evt.py +12 -8
- dissect/target/plugins/os/windows/log/evtx.py +9 -7
- dissect/target/plugins/os/windows/log/pfro.py +2 -1
- dissect/target/plugins/os/windows/network.py +2 -0
- dissect/target/plugins/os/windows/notifications.py +6 -4
- dissect/target/plugins/os/windows/prefetch.py +7 -2
- dissect/target/plugins/os/windows/regf/7zip.py +9 -1
- dissect/target/plugins/os/windows/regf/auditpol.py +2 -1
- dissect/target/plugins/os/windows/regf/bam.py +3 -1
- dissect/target/plugins/os/windows/regf/cit.py +14 -12
- dissect/target/plugins/os/windows/regf/clsid.py +6 -3
- dissect/target/plugins/os/windows/regf/firewall.py +2 -1
- dissect/target/plugins/os/windows/regf/mru.py +9 -8
- dissect/target/plugins/os/windows/regf/nethist.py +6 -3
- dissect/target/plugins/os/windows/regf/recentfilecache.py +3 -1
- dissect/target/plugins/os/windows/regf/regf.py +5 -1
- dissect/target/plugins/os/windows/regf/shimcache.py +1 -1
- dissect/target/plugins/os/windows/regf/usb.py +2 -1
- dissect/target/plugins/os/windows/regf/userassist.py +2 -1
- dissect/target/plugins/os/windows/registry.py +11 -0
- dissect/target/plugins/os/windows/services.py +3 -2
- dissect/target/plugins/os/windows/startupinfo.py +7 -2
- dissect/target/plugins/os/windows/syscache.py +3 -1
- dissect/target/plugins/os/windows/tasks.py +1 -1
- dissect/target/plugins/os/windows/thumbcache.py +11 -5
- dissect/target/plugins/os/windows/ual.py +12 -9
- dissect/target/plugins/os/windows/wua_history.py +0 -1
- dissect/target/tools/dump/utils.py +4 -0
- dissect/target/tools/shell.py +2 -1
- {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/METADATA +1 -1
- {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/RECORD +122 -123
- dissect/target/plugins/apps/texteditor/texteditor.py +0 -13
- dissect/target/plugins/os/unix/etc.py +0 -9
- /dissect/target/plugins/apps/{texteditor → editor}/__init__.py +0 -0
- {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/LICENSE +0 -0
- {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/WHEEL +0 -0
- {dissect.target-3.20.dev36.dist-info → dissect.target-3.20.dev39.dist-info}/entry_points.txt +0 -0
- {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
|
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) ->
|
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) ->
|
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) ->
|
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
|
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,
|
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="*") ->
|
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 = "*") ->
|
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 = "*") ->
|
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:
|
124
|
-
"""Parse Windows Eventlog files (
|
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) ->
|
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) ->
|
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,
|
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 (
|
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:
|
38
|
-
"""Return entries from Windows Event log files (
|
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
|
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) ->
|
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) ->
|
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
|
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
|
-
) ->
|
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
|
-
) ->
|
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
|
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(
|
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
|
-
|
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
|
-
|
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=
|
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
|