dissect.target 3.19.dev23__py3-none-any.whl → 3.19.dev25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dissect/target/plugins/filesystem/ntfs/mft.py +78 -17
- dissect/target/plugins/os/windows/regf/usb.py +179 -114
- {dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/METADATA +1 -1
- {dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/RECORD +9 -9
- {dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/LICENSE +0 -0
- {dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/WHEEL +0 -0
- {dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/entry_points.txt +0 -0
- {dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,10 @@
|
|
1
1
|
import logging
|
2
|
-
from typing import Callable
|
2
|
+
from typing import Callable, Iterator
|
3
3
|
|
4
4
|
from dissect.ntfs.attr import Attribute
|
5
5
|
from dissect.ntfs.c_ntfs import FILE_RECORD_SEGMENT_IN_USE
|
6
6
|
from dissect.ntfs.mft import MftRecord
|
7
|
+
from flow.record import Record
|
7
8
|
from flow.record.fieldtypes import windows_path
|
8
9
|
|
9
10
|
from dissect.target.exceptions import UnsupportedPluginError
|
@@ -53,7 +54,6 @@ FilesystemStdRecord = TargetRecordDescriptor(
|
|
53
54
|
],
|
54
55
|
)
|
55
56
|
|
56
|
-
|
57
57
|
FilesystemFilenameCompactRecord = TargetRecordDescriptor(
|
58
58
|
"filesystem/ntfs/mft/filename/compact",
|
59
59
|
[
|
@@ -90,6 +90,21 @@ FilesystemFilenameRecord = TargetRecordDescriptor(
|
|
90
90
|
],
|
91
91
|
)
|
92
92
|
|
93
|
+
FilesystemMACBRecord = TargetRecordDescriptor(
|
94
|
+
"filesystem/ntfs/mft/macb",
|
95
|
+
[
|
96
|
+
("datetime", "ts"),
|
97
|
+
("string", "macb"),
|
98
|
+
("uint32", "filename_index"),
|
99
|
+
("uint32", "segment"),
|
100
|
+
("path", "path"),
|
101
|
+
("string", "owner"),
|
102
|
+
("filesize", "filesize"),
|
103
|
+
("boolean", "resident"),
|
104
|
+
("boolean", "inuse"),
|
105
|
+
("string", "volume_uuid"),
|
106
|
+
],
|
107
|
+
)
|
93
108
|
|
94
109
|
RECORD_TYPES = {
|
95
110
|
InformationType.STANDARD_INFORMATION: FilesystemStdRecord,
|
@@ -118,7 +133,12 @@ class MftPlugin(Plugin):
|
|
118
133
|
]
|
119
134
|
)
|
120
135
|
@arg("--compact", action="store_true", help="compacts the MFT entry timestamps into a single record")
|
121
|
-
|
136
|
+
@arg(
|
137
|
+
"--macb",
|
138
|
+
action="store_true",
|
139
|
+
help="compacts the MFT entry timestamps into aggregated records with MACB bitfield",
|
140
|
+
)
|
141
|
+
def mft(self, compact: bool = False, macb: bool = False):
|
122
142
|
"""Return the MFT records of all NTFS filesystems.
|
123
143
|
|
124
144
|
The Master File Table (MFT) contains primarily metadata about every file and folder on a NFTS filesystem.
|
@@ -133,10 +153,19 @@ class MftPlugin(Plugin):
|
|
133
153
|
- https://docs.microsoft.com/en-us/windows/win32/fileio/master-file-table
|
134
154
|
"""
|
135
155
|
|
136
|
-
|
156
|
+
record_formatter = formatter
|
157
|
+
|
158
|
+
def noaggr(records: list[Record]) -> Iterator[Record]:
|
159
|
+
yield from records
|
160
|
+
|
161
|
+
aggr = noaggr
|
162
|
+
|
163
|
+
if compact and macb:
|
164
|
+
raise ValueError("--macb and --compact are mutually exclusive")
|
165
|
+
elif compact:
|
137
166
|
record_formatter = compacted_formatter
|
138
|
-
|
139
|
-
|
167
|
+
elif macb:
|
168
|
+
aggr = macb_aggr
|
140
169
|
|
141
170
|
for fs in self.target.filesystems:
|
142
171
|
if fs.__type__ != "ntfs":
|
@@ -167,17 +196,19 @@ class MftPlugin(Plugin):
|
|
167
196
|
|
168
197
|
for path in record.full_paths():
|
169
198
|
path = f"{drive_letter}{path}"
|
170
|
-
yield from
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
199
|
+
yield from aggr(
|
200
|
+
self.mft_records(
|
201
|
+
drive_letter=drive_letter,
|
202
|
+
record=record,
|
203
|
+
segment=record.segment,
|
204
|
+
path=path,
|
205
|
+
owner=owner,
|
206
|
+
size=size,
|
207
|
+
resident=resident,
|
208
|
+
inuse=inuse,
|
209
|
+
volume_uuid=volume_uuid,
|
210
|
+
record_formatter=record_formatter,
|
211
|
+
)
|
181
212
|
)
|
182
213
|
except Exception as e:
|
183
214
|
self.target.log.warning("An error occured parsing MFT segment %d: %s", record.segment, str(e))
|
@@ -275,3 +306,33 @@ def formatter(attr: Attribute, record_type: InformationType, **kwargs):
|
|
275
306
|
("A", attr.last_access_time),
|
276
307
|
]:
|
277
308
|
yield record_desc(ts=timestamp, ts_type=type, **kwargs)
|
309
|
+
|
310
|
+
|
311
|
+
def macb_aggr(records: list[Record]) -> Iterator[Record]:
|
312
|
+
def macb_set(bitfield, index, letter):
|
313
|
+
return bitfield[:index] + letter + bitfield[index + 1 :]
|
314
|
+
|
315
|
+
macbs = []
|
316
|
+
for record in records:
|
317
|
+
found = False
|
318
|
+
|
319
|
+
offset_std = int(record._desc.name == "filesystem/ntfs/mft/std") * 5
|
320
|
+
offset_ads = (int(record.ads) * 10) if offset_std == 0 else 0
|
321
|
+
|
322
|
+
field = "MACB".find(record.ts_type) + offset_std + offset_ads
|
323
|
+
for macb in macbs:
|
324
|
+
if macb.ts == record.ts:
|
325
|
+
macb.macb = macb_set(macb.macb, field, record.ts_type)
|
326
|
+
found = True
|
327
|
+
break
|
328
|
+
|
329
|
+
if found:
|
330
|
+
continue
|
331
|
+
|
332
|
+
macb = FilesystemMACBRecord.init_from_record(record)
|
333
|
+
macb.macb = "..../..../...."
|
334
|
+
macb.macb = macb_set(macb.macb, field, record.ts_type)
|
335
|
+
|
336
|
+
macbs.append(macb)
|
337
|
+
|
338
|
+
yield from macbs
|
@@ -1,29 +1,38 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import re
|
1
4
|
import struct
|
5
|
+
from typing import Iterator
|
2
6
|
|
3
7
|
from dissect.util.ts import wintimestamp
|
4
8
|
|
5
|
-
from dissect.target.exceptions import
|
9
|
+
from dissect.target.exceptions import (
|
10
|
+
RegistryKeyNotFoundError,
|
11
|
+
RegistryValueNotFoundError,
|
12
|
+
UnsupportedPluginError,
|
13
|
+
)
|
6
14
|
from dissect.target.helpers.record import TargetRecordDescriptor
|
7
|
-
from dissect.target.
|
15
|
+
from dissect.target.helpers.regutil import VirtualKey
|
16
|
+
from dissect.target.plugin import Plugin, export
|
8
17
|
|
9
18
|
UsbRegistryRecord = TargetRecordDescriptor(
|
10
19
|
"windows/registry/usb",
|
11
20
|
[
|
12
|
-
("string", "
|
21
|
+
("string", "type"),
|
13
22
|
("string", "serial"),
|
14
|
-
("string", "
|
15
|
-
("string", "pid"),
|
16
|
-
("string", "rev"),
|
17
|
-
("string", "containerid"),
|
23
|
+
("string", "container_id"),
|
18
24
|
("string", "vendor"),
|
19
25
|
("string", "product"),
|
20
|
-
("string", "
|
21
|
-
("string", "
|
26
|
+
("string", "revision"),
|
27
|
+
("string", "friendly_name"),
|
22
28
|
("datetime", "first_insert"),
|
23
29
|
("datetime", "first_install"),
|
24
30
|
("datetime", "last_insert"),
|
25
31
|
("datetime", "last_removal"),
|
26
|
-
("string", "
|
32
|
+
("string[]", "volumes"),
|
33
|
+
("string[]", "mounts"),
|
34
|
+
("string[]", "users"),
|
35
|
+
("path", "source"),
|
27
36
|
],
|
28
37
|
)
|
29
38
|
|
@@ -34,128 +43,184 @@ USB_DEVICE_PROPERTY_KEYS = {
|
|
34
43
|
"last_removal": ("0067", "00000067"), # Windows 8 and higer. USB device last removal date.
|
35
44
|
}
|
36
45
|
|
46
|
+
RE_DEVICE_NAME = re.compile(r"^(?P<type>.+?)&Ven_(?P<vendor>.+?)&Prod_(?P<product>.+?)(&Rev_(?P<revision>.+?))?$")
|
47
|
+
|
37
48
|
|
38
49
|
class UsbPlugin(Plugin):
|
39
|
-
"""USB plugin.
|
50
|
+
"""Windows USB history plugin.
|
51
|
+
|
52
|
+
Parses Windows registry data about attached USB devices. Does not parse EVTX EventIDs
|
53
|
+
or ``C:\\Windows\\inf\\setupapi(.dev).log``.
|
40
54
|
|
41
|
-
|
55
|
+
To get a full picture of the USB history on a Windows machine, you should parse the
|
56
|
+
relevant EventIDs using the evtx plugin. For more research on event log USB forensics, see:
|
57
|
+
- https://www.researchgate.net/publication/318514858
|
58
|
+
- https://dfir.pubpub.org/pub/h78di10n/release/2
|
59
|
+
- https://www.senturean.com/posts/19_08_03_usb_storage_forensics_1/#1-system-events
|
60
|
+
|
61
|
+
Resources:
|
62
|
+
- https://hatsoffsecurity.com/2014/06/05/usb-forensics-pt-1-serial-number/
|
63
|
+
- http://www.swiftforensics.com/2013/11/windows-8-new-registry-artifacts-part-1.html
|
64
|
+
- https://www.sans.org/blog/the-truth-about-usb-device-serial-numbers/
|
65
|
+
"""
|
66
|
+
|
67
|
+
# Stores history of mounted USB devices
|
42
68
|
USB_STOR = "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\USBSTOR"
|
43
|
-
# DeviceContainers holds all USB information. Only present in windows 8 or higher
|
44
|
-
DEVICE_CONTAINERS = "HKLM\\SYSTEM\\CurrentControlSet\\Control\\DeviceContainers"
|
45
|
-
USB = "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\USB"
|
46
|
-
HID = "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\HID"
|
47
|
-
SCSI = "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\SCSI"
|
48
69
|
|
49
|
-
|
50
|
-
|
51
|
-
raise UnsupportedPluginError(f"Registry key not found: {self.USB_STOR}")
|
70
|
+
# Stores the relation between a USB container_id and the FriendlyName of mounted volume(s) (Windows 7 and up)
|
71
|
+
PORTABLE_DEVICES = "HKLM\\SOFTWARE\\Microsoft\\Windows Portable Devices\\Devices"
|
52
72
|
|
53
|
-
|
54
|
-
|
55
|
-
"""
|
56
|
-
Params:
|
57
|
-
usb_reg_properties (Regf): A registry object with USB properties
|
58
|
-
Returns:
|
59
|
-
timestamps (Dict): A dict containing parsed timestamps within passed registry object
|
60
|
-
"""
|
61
|
-
usb_reg_properties = usb_reg_properties.subkey("{83da6326-97a6-4088-9453-a1923f573b29}")
|
62
|
-
timestamps = {}
|
63
|
-
|
64
|
-
for device_property, usbstor_values in USB_DEVICE_PROPERTY_KEYS.items():
|
65
|
-
for usb_val in usbstor_values:
|
66
|
-
if usb_val in [x.name for x in usb_reg_properties.subkeys()]:
|
67
|
-
version_key = usb_reg_properties.subkey(usb_val)
|
68
|
-
if "00000000" in version_key.subkeys():
|
69
|
-
data_value = version_key.subkey("00000000").value("Data").value
|
70
|
-
else:
|
71
|
-
data_value = version_key.value("(Default)").value
|
72
|
-
timestamps[device_property] = wintimestamp(struct.unpack("<Q", data_value)[0])
|
73
|
-
break
|
74
|
-
else:
|
75
|
-
timestamps[device_property] = None
|
76
|
-
return timestamps
|
73
|
+
# Stores the most recent mapping of a mount letter and a container_id
|
74
|
+
MOUNT_LETTER_MAP = "HKLM\\SYSTEM\\MountedDevices"
|
77
75
|
|
78
|
-
|
79
|
-
|
80
|
-
device_info = device_name.split("&")
|
81
|
-
device_type = device_info[0]
|
82
|
-
vendor = device_info[1].split("Ven_")[1]
|
83
|
-
product = device_info[2].split("Prod_")[1]
|
84
|
-
version = None if len(device_info) < 4 else device_info[3].split("Rev_")[1]
|
76
|
+
# User history of mount points accesses in explorer.exe
|
77
|
+
USER_MOUNTS = "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Mountpoints2"
|
85
78
|
|
86
|
-
|
79
|
+
# Other artifacts we currently do not parse:
|
80
|
+
# - "sysvol\Windows\inf\setupapi(.dev).log"
|
81
|
+
# - "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\USB"
|
82
|
+
# - "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\HID"
|
83
|
+
# - "HKLM\\SYSTEM\\CurrentControlSet\\Enum\\SCSI"
|
84
|
+
# - "HKLM\\SYSTEM\\CurrentControlSet\\Control\\DeviceContainers"
|
85
|
+
# - "SOFTWARE\Microsoft\Windows NT\CurrentVersion\EMDMgmt"
|
86
|
+
|
87
|
+
def check_compatible(self) -> None:
|
88
|
+
if not list(self.target.registry.keys(self.USB_STOR)):
|
89
|
+
raise UnsupportedPluginError(f"Registry key not found: {self.USB_STOR}")
|
87
90
|
|
88
91
|
@export(record=UsbRegistryRecord)
|
89
|
-
def usb(self):
|
90
|
-
"""
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
Yields UsbRegistryRecord with fields:
|
96
|
-
|
97
|
-
.. code-block:: text
|
98
|
-
|
99
|
-
hostname (string): The target hostname
|
100
|
-
domain (string): The target domain
|
101
|
-
type (string): Type of USB device
|
102
|
-
serial (string): Serial number of USB storage device
|
103
|
-
vid (string): Vendor ID of USB storage device
|
104
|
-
pid (string): Product ID of the USB storage device
|
105
|
-
rev (string): Version of the USB storage device
|
106
|
-
containerid (string):
|
107
|
-
friendlyname (string): Display name of the USB storage device
|
108
|
-
first_insert (datetime): First insertion date of USB storage device
|
109
|
-
first_install (datetime): First instalation date of USB storage device
|
110
|
-
last_insert (datetime): Most recent insertion (arrival) date of USB storage device
|
111
|
-
last_removal (datetime): Most recent removal (unplug) date of USB storage device
|
112
|
-
info_origin (string): Location of info present in output
|
92
|
+
def usb(self) -> Iterator[UsbRegistryRecord]:
|
93
|
+
"""Yields information about (historically) attached USB storage devices on Windows.
|
94
|
+
|
95
|
+
Uses the registry to find information about USB storage devices that have been attached to the system.
|
96
|
+
Also tries to find the past volume name and mount letters of the USB device and what user(s) interacted
|
97
|
+
with them using ``explorer.exe``.
|
113
98
|
"""
|
114
99
|
|
115
|
-
for
|
116
|
-
|
117
|
-
|
100
|
+
for key in self.target.registry.keys(self.USB_STOR):
|
101
|
+
for usb_type in key.subkeys():
|
102
|
+
try:
|
103
|
+
device_info = parse_device_name(usb_type.name)
|
104
|
+
except ValueError:
|
105
|
+
self.target.log.warning("Unable to parse USB device name: %s", usb_type.name)
|
106
|
+
device_info = {"type": None, "vendor": None, "product": None, "revision": None}
|
118
107
|
|
119
|
-
|
120
|
-
device_info = self.parse_device_name(usb_type.name)
|
121
|
-
usb_devices = usb_type.subkeys()
|
122
|
-
for usb_device in usb_devices:
|
123
|
-
properties = list(usb_device.subkeys())
|
108
|
+
for usb_device in usb_type.subkeys():
|
124
109
|
serial = usb_device.name
|
110
|
+
friendly_name = None
|
111
|
+
container_id = None
|
112
|
+
timestamps = {
|
113
|
+
"first_install": None,
|
114
|
+
"first_insert": None,
|
115
|
+
"last_insert": None,
|
116
|
+
"last_removal": None,
|
117
|
+
}
|
118
|
+
|
125
119
|
try:
|
126
|
-
|
127
|
-
# NOTE: make this more gracefull, windows 10 does not have the LogConf subkey
|
128
|
-
timestamps = (
|
129
|
-
self.unpack_timestamps(properties[2])
|
130
|
-
if len(properties) == 3
|
131
|
-
else self.unpack_timestamps(properties[1])
|
132
|
-
)
|
133
|
-
# ContainerIDs can be found back in USB and WdpBusEnumRoot
|
134
|
-
containerid = usb_device.value("ContainerID").value
|
120
|
+
friendly_name = usb_device.value("FriendlyName").value
|
135
121
|
except RegistryValueNotFoundError:
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
122
|
+
self.target.log.warning("No FriendlyName for USB with serial: %s", serial)
|
123
|
+
pass
|
124
|
+
|
125
|
+
try:
|
126
|
+
container_id = usb_device.value("ContainerID").value
|
127
|
+
except RegistryValueNotFoundError:
|
128
|
+
self.target.log.warning("No ContainerID for USB with serial: %s", serial)
|
129
|
+
|
130
|
+
try:
|
131
|
+
timestamps = unpack_timestamps(usb_device.subkey("Properties"))
|
132
|
+
except RegistryValueNotFoundError as e:
|
133
|
+
self.target.log.warning("Unable to parse USBSTOR registry properties for serial: %s", serial)
|
134
|
+
self.target.log.debug("", exc_info=e)
|
135
|
+
|
136
|
+
# We can check if any HKCU hive(s) are populated with the Volume GUID of the USB storage device.
|
137
|
+
# If a user has interacted with the mounted volume using explorer.exe we will get a match.
|
138
|
+
volumes = list(self.find_volumes(serial))
|
139
|
+
mounts = list(self.find_mounts(serial))
|
140
|
+
users = [
|
141
|
+
u.user.name for u in self.find_users([m[10:] for m in mounts if m.startswith("\\??\\Volume{")])
|
142
|
+
]
|
144
143
|
|
145
144
|
yield UsbRegistryRecord(
|
146
|
-
|
147
|
-
friendlyname=friendlyname,
|
145
|
+
friendly_name=friendly_name,
|
148
146
|
serial=serial,
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
first_insert=timestamps["first_insert"],
|
157
|
-
last_insert=timestamps["last_insert"], # AKA first arrival
|
158
|
-
last_removal=timestamps["last_removal"],
|
159
|
-
info_origin=info_origin,
|
147
|
+
container_id=container_id,
|
148
|
+
**device_info,
|
149
|
+
**timestamps,
|
150
|
+
volumes=volumes,
|
151
|
+
mounts=mounts,
|
152
|
+
users=users,
|
153
|
+
source=self.USB_STOR,
|
160
154
|
_target=self.target,
|
161
155
|
)
|
156
|
+
|
157
|
+
def find_volumes(self, serial: str) -> Iterator[str]:
|
158
|
+
"""Attempts to find mounted volume names for the given serial."""
|
159
|
+
serial = serial.lower()
|
160
|
+
try:
|
161
|
+
for device in self.target.registry.key(self.PORTABLE_DEVICES).subkeys():
|
162
|
+
if serial in device.name.lower():
|
163
|
+
yield device.value("FriendlyName").value
|
164
|
+
except RegistryKeyNotFoundError:
|
165
|
+
pass
|
166
|
+
|
167
|
+
def find_mounts(self, serial: str) -> Iterator[str]:
|
168
|
+
"""Attempts to find drive letters the given serial has been mounted on."""
|
169
|
+
serial = serial.lower()
|
170
|
+
try:
|
171
|
+
for mount in self.target.registry.key(self.MOUNT_LETTER_MAP).values():
|
172
|
+
try:
|
173
|
+
if serial in mount.value.decode("utf-16-le").lower():
|
174
|
+
yield mount.name.replace("\\DosDevices\\", "")
|
175
|
+
except UnicodeDecodeError:
|
176
|
+
pass
|
177
|
+
except RegistryKeyNotFoundError:
|
178
|
+
pass
|
179
|
+
|
180
|
+
def find_users(self, volume_guids: list[str]) -> Iterator[str]:
|
181
|
+
"""Attempt to find Windows users that have interacted with the given volume GUIDs."""
|
182
|
+
|
183
|
+
for volume_guid in volume_guids:
|
184
|
+
try:
|
185
|
+
for key in self.target.registry.key(self.USER_MOUNTS + "\\" + volume_guid):
|
186
|
+
yield self.target.registry.get_user_details(key)
|
187
|
+
except RegistryKeyNotFoundError:
|
188
|
+
pass
|
189
|
+
|
190
|
+
|
191
|
+
def unpack_timestamps(usb_reg_properties: VirtualKey) -> dict[str, int]:
|
192
|
+
"""Unpack relevant Windows timestamps from the provided USB registry properties subkey.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
usb_reg_properties: A registry object with USB properties.
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
A dict containing parsed timestamps within passed registry object.
|
199
|
+
"""
|
200
|
+
|
201
|
+
usb_reg_properties = usb_reg_properties.subkey("{83da6326-97a6-4088-9453-a1923f573b29}")
|
202
|
+
timestamps = {}
|
203
|
+
|
204
|
+
for device_property, usbstor_values in USB_DEVICE_PROPERTY_KEYS.items():
|
205
|
+
for usb_val in usbstor_values:
|
206
|
+
if usb_val in [x.name for x in usb_reg_properties.subkeys()]:
|
207
|
+
version_key = usb_reg_properties.subkey(usb_val)
|
208
|
+
if "00000000" in version_key.subkeys():
|
209
|
+
data_value = version_key.subkey("00000000").value("Data").value
|
210
|
+
else:
|
211
|
+
data_value = version_key.value("(Default)").value
|
212
|
+
timestamps[device_property] = wintimestamp(struct.unpack("<Q", data_value)[0])
|
213
|
+
break
|
214
|
+
else:
|
215
|
+
timestamps[device_property] = None
|
216
|
+
return timestamps
|
217
|
+
|
218
|
+
|
219
|
+
def parse_device_name(device_name: str) -> dict[str, str]:
|
220
|
+
"""Parse a registry device name into components."""
|
221
|
+
|
222
|
+
match = RE_DEVICE_NAME.match(device_name)
|
223
|
+
if not match:
|
224
|
+
raise ValueError(f"Unable to parse USB device name: {device_name}")
|
225
|
+
|
226
|
+
return match.groupdict()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dissect.target
|
3
|
-
Version: 3.19.
|
3
|
+
Version: 3.19.dev25
|
4
4
|
Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
6
6
|
License: Affero General Public License v3
|
@@ -166,7 +166,7 @@ dissect/target/plugins/filesystem/resolver.py,sha256=HfyASUFV4F9uD-yFXilFpPTORAs
|
|
166
166
|
dissect/target/plugins/filesystem/walkfs.py,sha256=e8HEZcV5Wiua26FGWL3xgiQ_PIhcNvGI5KCdsAx2Nmo,2298
|
167
167
|
dissect/target/plugins/filesystem/yara.py,sha256=JdWqbqDBhKrht3fTroqX7NpBU9khEQUWyMcDgLv2l2g,6686
|
168
168
|
dissect/target/plugins/filesystem/ntfs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
169
|
-
dissect/target/plugins/filesystem/ntfs/mft.py,sha256=
|
169
|
+
dissect/target/plugins/filesystem/ntfs/mft.py,sha256=2ibCLJA7yUrZshFSPKdjoNt3TpfwTtk-DaErghe91CM,11445
|
170
170
|
dissect/target/plugins/filesystem/ntfs/mft_timeline.py,sha256=vvNFAZbr7s3X2OTYf4ES_L6-XsouTXcTymfxnHfZ1Rw,6791
|
171
171
|
dissect/target/plugins/filesystem/ntfs/usnjrnl.py,sha256=uiT1ipmcAo__6VIUi8R_vvIu22vdnjMACKwLSAbzYjs,3704
|
172
172
|
dissect/target/plugins/filesystem/ntfs/utils.py,sha256=xG7Lgw9NX4tDDrZVRm0vycFVJTOM7j-HrjqzDh0f4uA,3136
|
@@ -316,7 +316,7 @@ dissect/target/plugins/os/windows/regf/runkeys.py,sha256=-2HcdnVytzCt1xwgAI8rHDn
|
|
316
316
|
dissect/target/plugins/os/windows/regf/shellbags.py,sha256=hXAqThFkHmGPmhNRSXwMNzw25kAyIC6OOZivgpPEwTQ,25679
|
317
317
|
dissect/target/plugins/os/windows/regf/shimcache.py,sha256=no78i0nxbnfgDJ5TpDZNAJggCigD_zLrXNYss7gdg2Q,9994
|
318
318
|
dissect/target/plugins/os/windows/regf/trusteddocs.py,sha256=3yvpBDM-Asg0rvGN2TwALGRm9DYogG6TxRau9D6FBbw,3700
|
319
|
-
dissect/target/plugins/os/windows/regf/usb.py,sha256=
|
319
|
+
dissect/target/plugins/os/windows/regf/usb.py,sha256=nSAHB4Cdd0wF2C1EK_XYOfWCyqOgTZCLfDhuSmr7rdM,9709
|
320
320
|
dissect/target/plugins/os/windows/regf/userassist.py,sha256=bSioEQdqUxdGwkdgMUfDIY2_pzrl9PdxPjmzmMaIwHs,5490
|
321
321
|
dissect/target/plugins/os/windows/task_helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
322
322
|
dissect/target/plugins/os/windows/task_helpers/tasks_job.py,sha256=7w3UGOiTAUQkP3xQ3sj4X3MTgHUJmmfdgiEadWmYquI,21197
|
@@ -346,10 +346,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
|
|
346
346
|
dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
|
347
347
|
dissect/target/volumes/md.py,sha256=j1K1iKmspl0C_OJFc7-Q1BMWN2OCC5EVANIgVlJ_fIE,1673
|
348
348
|
dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
|
349
|
-
dissect.target-3.19.
|
350
|
-
dissect.target-3.19.
|
351
|
-
dissect.target-3.19.
|
352
|
-
dissect.target-3.19.
|
353
|
-
dissect.target-3.19.
|
354
|
-
dissect.target-3.19.
|
355
|
-
dissect.target-3.19.
|
349
|
+
dissect.target-3.19.dev25.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
|
350
|
+
dissect.target-3.19.dev25.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
351
|
+
dissect.target-3.19.dev25.dist-info/METADATA,sha256=7Zg79geLIProzjOZaFpDxr0Zfurfq0EgleNkmo8sI5E,12719
|
352
|
+
dissect.target-3.19.dev25.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
353
|
+
dissect.target-3.19.dev25.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
|
354
|
+
dissect.target-3.19.dev25.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
355
|
+
dissect.target-3.19.dev25.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
{dissect.target-3.19.dev23.dist-info → dissect.target-3.19.dev25.dist-info}/entry_points.txt
RENAMED
File without changes
|
File without changes
|