dissect.target 3.20.dev23__py3-none-any.whl → 3.20.dev26__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/filesystems/btrfs.py +4 -1
 - dissect/target/filesystems/ntfs.py +18 -2
 - dissect/target/plugins/os/windows/regf/shellbags.py +351 -345
 - {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/METADATA +1 -1
 - {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/RECORD +10 -10
 - {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/COPYRIGHT +0 -0
 - {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/LICENSE +0 -0
 - {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/WHEEL +0 -0
 - {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/entry_points.txt +0 -0
 - {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/top_level.txt +0 -0
 
| 
         @@ -181,6 +181,9 @@ class BtrfsFilesystemEntry(FilesystemEntry): 
     | 
|
| 
       181 
181 
     | 
    
         | 
| 
       182 
182 
     | 
    
         
             
                    # Add block information of the filesystem
         
     | 
| 
       183 
183 
     | 
    
         
             
                    st_info.st_blksize = entry.btrfs.sector_size
         
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                    st_info.st_blocks = 0
         
     | 
| 
      
 186 
     | 
    
         
            +
                    if not self.is_dir():
         
     | 
| 
      
 187 
     | 
    
         
            +
                        st_info.st_blocks = (st_info.st_blksize // 512) * math.ceil(st_info.st_size / st_info.st_blksize)
         
     | 
| 
       185 
188 
     | 
    
         | 
| 
       186 
189 
     | 
    
         
             
                    return st_info
         
     | 
| 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            import math
         
     | 
| 
       3 
4 
     | 
    
         
             
            import stat
         
     | 
| 
       4 
5 
     | 
    
         
             
            from typing import BinaryIO, Iterator, Optional
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
         @@ -151,12 +152,14 @@ class NtfsFilesystemEntry(FilesystemEntry): 
     | 
|
| 
       151 
152 
     | 
    
         
             
                    record = self.dereference()
         
     | 
| 
       152 
153 
     | 
    
         | 
| 
       153 
154 
     | 
    
         
             
                    size = 0
         
     | 
| 
      
 155 
     | 
    
         
            +
                    real_size = 0
         
     | 
| 
       154 
156 
     | 
    
         
             
                    if self.is_symlink():
         
     | 
| 
       155 
157 
     | 
    
         
             
                        mode = stat.S_IFLNK
         
     | 
| 
       156 
158 
     | 
    
         
             
                    elif self.is_file():
         
     | 
| 
       157 
159 
     | 
    
         
             
                        mode = stat.S_IFREG
         
     | 
| 
       158 
160 
     | 
    
         
             
                        try:
         
     | 
| 
       159 
161 
     | 
    
         
             
                            size = record.size(self.ads)
         
     | 
| 
      
 162 
     | 
    
         
            +
                            real_size = record.size(self.ads, allocated=True)
         
     | 
| 
       160 
163 
     | 
    
         
             
                        except NtfsFileNotFoundError as e:
         
     | 
| 
       161 
164 
     | 
    
         
             
                            # Occurs when it cannot find the the specific ads inside its attributes
         
     | 
| 
       162 
165 
     | 
    
         
             
                            raise FileNotFoundError from e
         
     | 
| 
         @@ -176,16 +179,29 @@ class NtfsFilesystemEntry(FilesystemEntry): 
     | 
|
| 
       176 
179 
     | 
    
         
             
                            0,
         
     | 
| 
       177 
180 
     | 
    
         
             
                            size,
         
     | 
| 
       178 
181 
     | 
    
         
             
                            stdinfo.last_access_time.timestamp(),
         
     | 
| 
       179 
     | 
    
         
            -
                            stdinfo. 
     | 
| 
      
 182 
     | 
    
         
            +
                            stdinfo.last_modification_time.timestamp(),
         
     | 
| 
      
 183 
     | 
    
         
            +
                            # ctime gets set to creation time for python <3.12 purposes
         
     | 
| 
       180 
184 
     | 
    
         
             
                            stdinfo.creation_time.timestamp(),
         
     | 
| 
       181 
185 
     | 
    
         
             
                        ]
         
     | 
| 
       182 
186 
     | 
    
         
             
                    )
         
     | 
| 
       183 
187 
     | 
    
         | 
| 
       184 
188 
     | 
    
         
             
                    # Set the nanosecond resolution separately
         
     | 
| 
       185 
189 
     | 
    
         
             
                    st_info.st_atime_ns = stdinfo.last_access_time_ns
         
     | 
| 
       186 
     | 
    
         
            -
                    st_info.st_mtime_ns = stdinfo. 
     | 
| 
      
 190 
     | 
    
         
            +
                    st_info.st_mtime_ns = stdinfo.last_modification_time_ns
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
       187 
192 
     | 
    
         
             
                    st_info.st_ctime_ns = stdinfo.creation_time_ns
         
     | 
| 
       188 
193 
     | 
    
         | 
| 
      
 194 
     | 
    
         
            +
                    st_info.st_birthtime = stdinfo.creation_time.timestamp()
         
     | 
| 
      
 195 
     | 
    
         
            +
                    st_info.st_birthtime_ns = stdinfo.creation_time_ns
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                    # real_size is none if the size is resident
         
     | 
| 
      
 198 
     | 
    
         
            +
                    st_info.st_blksize = record.ntfs.cluster_size
         
     | 
| 
      
 199 
     | 
    
         
            +
                    blocks = 0
         
     | 
| 
      
 200 
     | 
    
         
            +
                    if not record.resident:
         
     | 
| 
      
 201 
     | 
    
         
            +
                        blocks = math.ceil(real_size / 512)
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                    st_info.st_blocks = blocks
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
       189 
205 
     | 
    
         
             
                    return st_info
         
     | 
| 
       190 
206 
     | 
    
         | 
| 
       191 
207 
     | 
    
         
             
                def attr(self) -> AttributeMap:
         
     | 
| 
         @@ -1,6 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from __future__ import annotations
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            import io
         
     | 
| 
       2 
4 
     | 
    
         
             
            import logging
         
     | 
| 
       3 
5 
     | 
    
         
             
            import uuid
         
     | 
| 
      
 6 
     | 
    
         
            +
            from datetime import datetime
         
     | 
| 
      
 7 
     | 
    
         
            +
            from typing import Any, Iterator
         
     | 
| 
       4 
8 
     | 
    
         | 
| 
       5 
9 
     | 
    
         
             
            from dissect.cstruct import cstruct
         
     | 
| 
       6 
10 
     | 
    
         
             
            from dissect.util.ts import dostimestamp
         
     | 
| 
         @@ -13,7 +17,9 @@ from dissect.target.helpers.descriptor_extensions import ( 
     | 
|
| 
       13 
17 
     | 
    
         
             
                UserRecordDescriptorExtension,
         
     | 
| 
       14 
18 
     | 
    
         
             
            )
         
     | 
| 
       15 
19 
     | 
    
         
             
            from dissect.target.helpers.record import create_extended_descriptor
         
     | 
| 
      
 20 
     | 
    
         
            +
            from dissect.target.helpers.regutil import RegistryKey
         
     | 
| 
       16 
21 
     | 
    
         
             
            from dissect.target.plugin import Plugin, export
         
     | 
| 
      
 22 
     | 
    
         
            +
            from dissect.target.target import Target
         
     | 
| 
       17 
23 
     | 
    
         | 
| 
       18 
24 
     | 
    
         
             
            log = logging.getLogger(__name__)
         
     | 
| 
       19 
25 
     | 
    
         | 
| 
         @@ -170,30 +176,30 @@ struct SHITEM_MTP_VOLUME_GUID { 
     | 
|
| 
       170 
176 
     | 
    
         
             
            };
         
     | 
| 
       171 
177 
     | 
    
         | 
| 
       172 
178 
     | 
    
         
             
            struct SHITEM_MTP_VOLUME {
         
     | 
| 
       173 
     | 
    
         
            -
                uint16 
     | 
| 
       174 
     | 
    
         
            -
                uint8 
     | 
| 
       175 
     | 
    
         
            -
                uint8 
     | 
| 
       176 
     | 
    
         
            -
                uint16 
     | 
| 
       177 
     | 
    
         
            -
                uint32 
     | 
| 
       178 
     | 
    
         
            -
                uint32 
     | 
| 
       179 
     | 
    
         
            -
                uint16 
     | 
| 
       180 
     | 
    
         
            -
                uint16 
     | 
| 
       181 
     | 
    
         
            -
                uint16 
     | 
| 
       182 
     | 
    
         
            -
                uint16 
     | 
| 
       183 
     | 
    
         
            -
                uint32 
     | 
| 
       184 
     | 
    
         
            -
                uint64 
     | 
| 
       185 
     | 
    
         
            -
                uint32 
     | 
| 
       186 
     | 
    
         
            -
                uint32 
     | 
| 
       187 
     | 
    
         
            -
                uint32 
     | 
| 
       188 
     | 
    
         
            -
                uint32 
     | 
| 
       189 
     | 
    
         
            -
                uint32 
     | 
| 
       190 
     | 
    
         
            -
                wchar 
     | 
| 
       191 
     | 
    
         
            -
                wchar 
     | 
| 
       192 
     | 
    
         
            -
                wchar 
     | 
| 
       193 
     | 
    
         
            -
                SHITEM_MTP_VOLUME_GUID 
     | 
| 
       194 
     | 
    
         
            -
                uint32 
     | 
| 
       195 
     | 
    
         
            -
                char 
     | 
| 
       196 
     | 
    
         
            -
                uint32 
     | 
| 
      
 179 
     | 
    
         
            +
                uint16                      size;
         
     | 
| 
      
 180 
     | 
    
         
            +
                uint8                       type;
         
     | 
| 
      
 181 
     | 
    
         
            +
                uint8                       unk0;
         
     | 
| 
      
 182 
     | 
    
         
            +
                uint16                      data_size;
         
     | 
| 
      
 183 
     | 
    
         
            +
                uint32                      data_signature;
         
     | 
| 
      
 184 
     | 
    
         
            +
                uint32                      unk1;
         
     | 
| 
      
 185 
     | 
    
         
            +
                uint16                      unk2;
         
     | 
| 
      
 186 
     | 
    
         
            +
                uint16                      unk3;
         
     | 
| 
      
 187 
     | 
    
         
            +
                uint16                      unk4;
         
     | 
| 
      
 188 
     | 
    
         
            +
                uint16                      unk5;
         
     | 
| 
      
 189 
     | 
    
         
            +
                uint32                      unk6;
         
     | 
| 
      
 190 
     | 
    
         
            +
                uint64                      unk7;
         
     | 
| 
      
 191 
     | 
    
         
            +
                uint32                      unk8;
         
     | 
| 
      
 192 
     | 
    
         
            +
                uint32                      name_size;
         
     | 
| 
      
 193 
     | 
    
         
            +
                uint32                      identifier_size;
         
     | 
| 
      
 194 
     | 
    
         
            +
                uint32                      filesystem_size;
         
     | 
| 
      
 195 
     | 
    
         
            +
                uint32                      num_guid;
         
     | 
| 
      
 196 
     | 
    
         
            +
                wchar                       name[name_size];
         
     | 
| 
      
 197 
     | 
    
         
            +
                wchar                       identifier[identifier_size];
         
     | 
| 
      
 198 
     | 
    
         
            +
                wchar                       filesystem[filesystem_size];
         
     | 
| 
      
 199 
     | 
    
         
            +
                SHITEM_MTP_VOLUME_GUID      guids[num_guid];
         
     | 
| 
      
 200 
     | 
    
         
            +
                uint32                      unk9;
         
     | 
| 
      
 201 
     | 
    
         
            +
                char                        class_identifier[16];
         
     | 
| 
      
 202 
     | 
    
         
            +
                uint32                      num_properties;
         
     | 
| 
       197 
203 
     | 
    
         
             
            };
         
     | 
| 
       198 
204 
     | 
    
         | 
| 
       199 
205 
     | 
    
         
             
            struct SHITEM_USERS_PROPERTY_VIEW {
         
     | 
| 
         @@ -248,267 +254,6 @@ c_bag = cstruct().load(bag_def) 
     | 
|
| 
       248 
254 
     | 
    
         
             
            DELEGATE_ITEM_IDENTIFIER = b"\x74\x1a\x59\x5e\x96\xdf\xd3\x48\x8d\x67\x17\x33\xbc\xee\x28\xba"
         
     | 
| 
       249 
255 
     | 
    
         | 
| 
       250 
256 
     | 
    
         | 
| 
       251 
     | 
    
         
            -
            ShellBagRecord = create_extended_descriptor([RegistryRecordDescriptorExtension, UserRecordDescriptorExtension])(
         
     | 
| 
       252 
     | 
    
         
            -
                "windows/shellbag",
         
     | 
| 
       253 
     | 
    
         
            -
                [
         
     | 
| 
       254 
     | 
    
         
            -
                    ("path", "path"),
         
     | 
| 
       255 
     | 
    
         
            -
                    ("datetime", "creation_time"),
         
     | 
| 
       256 
     | 
    
         
            -
                    ("datetime", "modification_time"),
         
     | 
| 
       257 
     | 
    
         
            -
                    ("datetime", "access_time"),
         
     | 
| 
       258 
     | 
    
         
            -
                    ("datetime", "regf_modification_time"),
         
     | 
| 
       259 
     | 
    
         
            -
                ],
         
     | 
| 
       260 
     | 
    
         
            -
            )
         
     | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
       263 
     | 
    
         
            -
            class ShellBagsPlugin(Plugin):
         
     | 
| 
       264 
     | 
    
         
            -
                """Windows Shellbags plugin.
         
     | 
| 
       265 
     | 
    
         
            -
             
     | 
| 
       266 
     | 
    
         
            -
                References:
         
     | 
| 
       267 
     | 
    
         
            -
                    - https://github.com/libyal/libfwsi
         
     | 
| 
       268 
     | 
    
         
            -
                """
         
     | 
| 
       269 
     | 
    
         
            -
             
     | 
| 
       270 
     | 
    
         
            -
                KEYS = [
         
     | 
| 
       271 
     | 
    
         
            -
                    "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell",
         
     | 
| 
       272 
     | 
    
         
            -
                    "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\ShellNoRoam",
         
     | 
| 
       273 
     | 
    
         
            -
                    "HKEY_CURRENT_USER\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell",
         
     | 
| 
       274 
     | 
    
         
            -
                    "HKEY_CURRENT_USER\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\ShellNoRoam",
         
     | 
| 
       275 
     | 
    
         
            -
                    "HKEY_CURRENT_USER\\Software\\Classes\\Wow6432Node\\Local Settings\\Software\\Microsoft\\Windows\\Shell",
         
     | 
| 
       276 
     | 
    
         
            -
                    "HKEY_CURRENT_USER\\Software\\Classes\\Wow6432Node\\Local Settings\\Software\\Microsoft\\Windows\\ShellNoRoam",
         
     | 
| 
       277 
     | 
    
         
            -
                    "HKEY_CURRENT_USER\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU",
         
     | 
| 
       278 
     | 
    
         
            -
                ]
         
     | 
| 
       279 
     | 
    
         
            -
             
     | 
| 
       280 
     | 
    
         
            -
                def __init__(self, target):
         
     | 
| 
       281 
     | 
    
         
            -
                    super().__init__(target)
         
     | 
| 
       282 
     | 
    
         
            -
                    self.bagkeys = list(self.target.registry.keys(self.KEYS))
         
     | 
| 
       283 
     | 
    
         
            -
             
     | 
| 
       284 
     | 
    
         
            -
                def check_compatible(self) -> None:
         
     | 
| 
       285 
     | 
    
         
            -
                    if not len(self.bagkeys) > 0:
         
     | 
| 
       286 
     | 
    
         
            -
                        raise UnsupportedPluginError("No shellbags found")
         
     | 
| 
       287 
     | 
    
         
            -
             
     | 
| 
       288 
     | 
    
         
            -
                @export(record=ShellBagRecord)
         
     | 
| 
       289 
     | 
    
         
            -
                def shellbags(self):
         
     | 
| 
       290 
     | 
    
         
            -
                    """Return Windows Shellbags.
         
     | 
| 
       291 
     | 
    
         
            -
             
     | 
| 
       292 
     | 
    
         
            -
                    Shellbags are registry keys to improve user experience when using Windows Explorer. It stores information about
         
     | 
| 
       293 
     | 
    
         
            -
                    for example file/folder creation time and access time.
         
     | 
| 
       294 
     | 
    
         
            -
             
     | 
| 
       295 
     | 
    
         
            -
                    References:
         
     | 
| 
       296 
     | 
    
         
            -
                        - https://www.hackingarticles.in/forensic-investigation-shellbags/
         
     | 
| 
       297 
     | 
    
         
            -
                    """
         
     | 
| 
       298 
     | 
    
         
            -
                    for regkey in self.bagkeys:
         
     | 
| 
       299 
     | 
    
         
            -
                        try:
         
     | 
| 
       300 
     | 
    
         
            -
                            bagsmru = regkey.subkey("BagMRU")
         
     | 
| 
       301 
     | 
    
         
            -
             
     | 
| 
       302 
     | 
    
         
            -
                            for r in self._walk_bags(bagsmru, None):
         
     | 
| 
       303 
     | 
    
         
            -
                                yield r
         
     | 
| 
       304 
     | 
    
         
            -
                        except RegistryKeyNotFoundError:
         
     | 
| 
       305 
     | 
    
         
            -
                            continue
         
     | 
| 
       306 
     | 
    
         
            -
                        except Exception:  # noqa
         
     | 
| 
       307 
     | 
    
         
            -
                            self.target.log.exception("Exception while parsing shellbags")
         
     | 
| 
       308 
     | 
    
         
            -
                            continue
         
     | 
| 
       309 
     | 
    
         
            -
             
     | 
| 
       310 
     | 
    
         
            -
                def _walk_bags(self, key, path_prefix):
         
     | 
| 
       311 
     | 
    
         
            -
                    path_prefix = [] if path_prefix is None else [path_prefix]
         
     | 
| 
       312 
     | 
    
         
            -
             
     | 
| 
       313 
     | 
    
         
            -
                    user = self.target.registry.get_user(key)
         
     | 
| 
       314 
     | 
    
         
            -
             
     | 
| 
       315 
     | 
    
         
            -
                    for reg_val in key.values():
         
     | 
| 
       316 
     | 
    
         
            -
                        name, value = reg_val.name, reg_val.value
         
     | 
| 
       317 
     | 
    
         
            -
                        if not name.isdigit():
         
     | 
| 
       318 
     | 
    
         
            -
                            continue
         
     | 
| 
       319 
     | 
    
         
            -
                        path = None
         
     | 
| 
       320 
     | 
    
         
            -
             
     | 
| 
       321 
     | 
    
         
            -
                        for item in parse_shell_item_list(value):
         
     | 
| 
       322 
     | 
    
         
            -
                            path = "\\".join(path_prefix + [item.name])
         
     | 
| 
       323 
     | 
    
         
            -
                            yield ShellBagRecord(
         
     | 
| 
       324 
     | 
    
         
            -
                                path=windows_path(path),
         
     | 
| 
       325 
     | 
    
         
            -
                                creation_time=item.creation_time,
         
     | 
| 
       326 
     | 
    
         
            -
                                modification_time=item.modification_time,
         
     | 
| 
       327 
     | 
    
         
            -
                                access_time=item.access_time,
         
     | 
| 
       328 
     | 
    
         
            -
                                regf_modification_time=key.ts,
         
     | 
| 
       329 
     | 
    
         
            -
                                _target=self.target,
         
     | 
| 
       330 
     | 
    
         
            -
                                _user=user,
         
     | 
| 
       331 
     | 
    
         
            -
                                _key=key,
         
     | 
| 
       332 
     | 
    
         
            -
                            )
         
     | 
| 
       333 
     | 
    
         
            -
             
     | 
| 
       334 
     | 
    
         
            -
                        for r in self._walk_bags(key.subkey(name), path):
         
     | 
| 
       335 
     | 
    
         
            -
                            yield r
         
     | 
| 
       336 
     | 
    
         
            -
             
     | 
| 
       337 
     | 
    
         
            -
             
     | 
| 
       338 
     | 
    
         
            -
            def parse_shell_item_list(buf):
         
     | 
| 
       339 
     | 
    
         
            -
                offset = 0
         
     | 
| 
       340 
     | 
    
         
            -
                end = len(buf)
         
     | 
| 
       341 
     | 
    
         
            -
                list_buf = memoryview(buf)
         
     | 
| 
       342 
     | 
    
         
            -
             
     | 
| 
       343 
     | 
    
         
            -
                parent = None
         
     | 
| 
       344 
     | 
    
         
            -
                while offset < end:
         
     | 
| 
       345 
     | 
    
         
            -
                    size = c_bag.uint16(list_buf[offset : offset + 2])
         
     | 
| 
       346 
     | 
    
         
            -
             
     | 
| 
       347 
     | 
    
         
            -
                    if size == 0:
         
     | 
| 
       348 
     | 
    
         
            -
                        break
         
     | 
| 
       349 
     | 
    
         
            -
             
     | 
| 
       350 
     | 
    
         
            -
                    item_buf = list_buf[offset : offset + size]
         
     | 
| 
       351 
     | 
    
         
            -
             
     | 
| 
       352 
     | 
    
         
            -
                    entry = None
         
     | 
| 
       353 
     | 
    
         
            -
                    if size >= 8:
         
     | 
| 
       354 
     | 
    
         
            -
                        signature = c_bag.uint32(item_buf[4:8])
         
     | 
| 
       355 
     | 
    
         
            -
                        if signature == 0x39DE2184:
         
     | 
| 
       356 
     | 
    
         
            -
                            entry = CONTROL_PANEL_CATEGORY
         
     | 
| 
       357 
     | 
    
         
            -
                        elif signature == 0x4D677541:
         
     | 
| 
       358 
     | 
    
         
            -
                            entry = CDBURN
         
     | 
| 
       359 
     | 
    
         
            -
                        elif signature == 0x49534647:
         
     | 
| 
       360 
     | 
    
         
            -
                            entry = GAME_FOLDER
         
     | 
| 
       361 
     | 
    
         
            -
                        elif signature == 0xFFFFFF38:
         
     | 
| 
       362 
     | 
    
         
            -
                            entry = CONTROL_PANEL_CPL_FILE
         
     | 
| 
       363 
     | 
    
         
            -
             
     | 
| 
       364 
     | 
    
         
            -
                    if size >= 10 and not entry:
         
     | 
| 
       365 
     | 
    
         
            -
                        signature = c_bag.uint32(item_buf[6:10])
         
     | 
| 
       366 
     | 
    
         
            -
                        if signature == 0x07192006:
         
     | 
| 
       367 
     | 
    
         
            -
                            entry = MTP_FILE_ENTRY
         
     | 
| 
       368 
     | 
    
         
            -
                        elif signature == 0x10312005:
         
     | 
| 
       369 
     | 
    
         
            -
                            entry = MTP_VOLUME
         
     | 
| 
       370 
     | 
    
         
            -
                        elif signature in (0x10141981, 0x23A3DFD5, 0x23FEBBEE, 0x3B93AFBB, 0xBEEBEE00):
         
     | 
| 
       371 
     | 
    
         
            -
                            entry = USERS_PROPERTY_VIEW
         
     | 
| 
       372 
     | 
    
         
            -
                        elif signature == 0x46534643:
         
     | 
| 
       373 
     | 
    
         
            -
                            entry = UNKNOWN_0x74
         
     | 
| 
       374 
     | 
    
         
            -
             
     | 
| 
       375 
     | 
    
         
            -
                    if size >= 38 and not entry:
         
     | 
| 
       376 
     | 
    
         
            -
                        if item_buf[size - 32 : size] == DELEGATE_ITEM_IDENTIFIER:
         
     | 
| 
       377 
     | 
    
         
            -
                            entry = DELEGATE
         
     | 
| 
       378 
     | 
    
         
            -
             
     | 
| 
       379 
     | 
    
         
            -
                    if size >= 3 and not entry:
         
     | 
| 
       380 
     | 
    
         
            -
                        class_type = item_buf[2]
         
     | 
| 
       381 
     | 
    
         
            -
                        mask_type = class_type & 0x70
         
     | 
| 
       382 
     | 
    
         
            -
             
     | 
| 
       383 
     | 
    
         
            -
                        if mask_type == 0x00:
         
     | 
| 
       384 
     | 
    
         
            -
                            if class_type == 0x00:
         
     | 
| 
       385 
     | 
    
         
            -
                                entry = UNKNOWN0
         
     | 
| 
       386 
     | 
    
         
            -
                            elif class_type == 0x01:
         
     | 
| 
       387 
     | 
    
         
            -
                                entry = UNKNOWN1
         
     | 
| 
       388 
     | 
    
         
            -
             
     | 
| 
       389 
     | 
    
         
            -
                        elif mask_type == 0x10:
         
     | 
| 
       390 
     | 
    
         
            -
                            if class_type == 0x1F:
         
     | 
| 
       391 
     | 
    
         
            -
                                entry = ROOT_FOLDER
         
     | 
| 
       392 
     | 
    
         
            -
             
     | 
| 
       393 
     | 
    
         
            -
                        elif mask_type == 0x20:
         
     | 
| 
       394 
     | 
    
         
            -
                            if class_type in (0x23, 0x25, 0x29, 0x2A, 0x2E, 0x2F):
         
     | 
| 
       395 
     | 
    
         
            -
                                entry = VOLUME
         
     | 
| 
       396 
     | 
    
         
            -
             
     | 
| 
       397 
     | 
    
         
            -
                        elif mask_type == 0x30:
         
     | 
| 
       398 
     | 
    
         
            -
                            if class_type in (0x30, 0x31, 0x32, 0x35, 0x36, 0xB1):
         
     | 
| 
       399 
     | 
    
         
            -
                                entry = FILE_ENTRY
         
     | 
| 
       400 
     | 
    
         
            -
             
     | 
| 
       401 
     | 
    
         
            -
                        elif mask_type == 0x40:
         
     | 
| 
       402 
     | 
    
         
            -
                            if class_type in (0x41, 0x42, 0x46, 0x47, 0x4C, 0xC3):
         
     | 
| 
       403 
     | 
    
         
            -
                                entry = NETWORK
         
     | 
| 
       404 
     | 
    
         
            -
             
     | 
| 
       405 
     | 
    
         
            -
                        elif mask_type == 0x50:
         
     | 
| 
       406 
     | 
    
         
            -
                            if class_type == 0x52:
         
     | 
| 
       407 
     | 
    
         
            -
                                entry = COMPRESSED_FOLDER
         
     | 
| 
       408 
     | 
    
         
            -
             
     | 
| 
       409 
     | 
    
         
            -
                        elif mask_type == 0x60:
         
     | 
| 
       410 
     | 
    
         
            -
                            if class_type == 0x61:
         
     | 
| 
       411 
     | 
    
         
            -
                                entry = URI
         
     | 
| 
       412 
     | 
    
         
            -
             
     | 
| 
       413 
     | 
    
         
            -
                        elif mask_type == 0x70:
         
     | 
| 
       414 
     | 
    
         
            -
                            if class_type == 0x71:
         
     | 
| 
       415 
     | 
    
         
            -
                                entry = CONTROL_PANEL
         
     | 
| 
       416 
     | 
    
         
            -
                        else:
         
     | 
| 
       417 
     | 
    
         
            -
                            if not entry:
         
     | 
| 
       418 
     | 
    
         
            -
                                log.debug("No supported shell item found for size 0x%04x and type 0x%02x", size, class_type)
         
     | 
| 
       419 
     | 
    
         
            -
                                entry = UNKNOWN
         
     | 
| 
       420 
     | 
    
         
            -
             
     | 
| 
       421 
     | 
    
         
            -
                    if not entry:
         
     | 
| 
       422 
     | 
    
         
            -
                        log.debug("No supported shell item found for size 0x%04x", size)
         
     | 
| 
       423 
     | 
    
         
            -
                        entry = UNKNOWN
         
     | 
| 
       424 
     | 
    
         
            -
             
     | 
| 
       425 
     | 
    
         
            -
                    entry = entry(item_buf)
         
     | 
| 
       426 
     | 
    
         
            -
                    entry.parent = parent
         
     | 
| 
       427 
     | 
    
         
            -
             
     | 
| 
       428 
     | 
    
         
            -
                    first_extension_block_offset = c_bag.uint16(item_buf[-2:])
         
     | 
| 
       429 
     | 
    
         
            -
                    if 4 <= first_extension_block_offset < size - 2:
         
     | 
| 
       430 
     | 
    
         
            -
                        extension_offset = first_extension_block_offset
         
     | 
| 
       431 
     | 
    
         
            -
                        while extension_offset < size - 2:
         
     | 
| 
       432 
     | 
    
         
            -
                            extension_size = c_bag.uint16(item_buf[extension_offset : extension_offset + 2])
         
     | 
| 
       433 
     | 
    
         
            -
             
     | 
| 
       434 
     | 
    
         
            -
                            if extension_size == 0:
         
     | 
| 
       435 
     | 
    
         
            -
                                break
         
     | 
| 
       436 
     | 
    
         
            -
             
     | 
| 
       437 
     | 
    
         
            -
                            if extension_size > size - extension_offset:
         
     | 
| 
       438 
     | 
    
         
            -
                                log.debug(
         
     | 
| 
       439 
     | 
    
         
            -
                                    "Extension size exceeds item size: 0x%04x > 0x%04x - 0x%04x",
         
     | 
| 
       440 
     | 
    
         
            -
                                    extension_size,
         
     | 
| 
       441 
     | 
    
         
            -
                                    size,
         
     | 
| 
       442 
     | 
    
         
            -
                                    extension_offset,
         
     | 
| 
       443 
     | 
    
         
            -
                                )
         
     | 
| 
       444 
     | 
    
         
            -
                                break  # Extension size too large
         
     | 
| 
       445 
     | 
    
         
            -
             
     | 
| 
       446 
     | 
    
         
            -
                            extension_buf = item_buf[extension_offset : extension_offset + extension_size]
         
     | 
| 
       447 
     | 
    
         
            -
                            extension_signature = c_bag.uint32(extension_buf[4:8])
         
     | 
| 
       448 
     | 
    
         
            -
             
     | 
| 
       449 
     | 
    
         
            -
                            ext = None
         
     | 
| 
       450 
     | 
    
         
            -
             
     | 
| 
       451 
     | 
    
         
            -
                            if extension_signature >> 16 != 0xBEEF:
         
     | 
| 
       452 
     | 
    
         
            -
                                log.debug("Got unsupported extension signature 0x%08x from item %r", extension_signature, entry)
         
     | 
| 
       453 
     | 
    
         
            -
                                pass  # Unsupported
         
     | 
| 
       454 
     | 
    
         
            -
             
     | 
| 
       455 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0000:
         
     | 
| 
       456 
     | 
    
         
            -
                                pass
         
     | 
| 
       457 
     | 
    
         
            -
             
     | 
| 
       458 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0001:
         
     | 
| 
       459 
     | 
    
         
            -
                                pass
         
     | 
| 
       460 
     | 
    
         
            -
             
     | 
| 
       461 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0003:
         
     | 
| 
       462 
     | 
    
         
            -
                                ext = EXTENSION_BLOCK_BEEF0004
         
     | 
| 
       463 
     | 
    
         
            -
             
     | 
| 
       464 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0004:
         
     | 
| 
       465 
     | 
    
         
            -
                                ext = EXTENSION_BLOCK_BEEF0004
         
     | 
| 
       466 
     | 
    
         
            -
             
     | 
| 
       467 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0005:
         
     | 
| 
       468 
     | 
    
         
            -
                                ext = EXTENSION_BLOCK_BEEF0005
         
     | 
| 
       469 
     | 
    
         
            -
             
     | 
| 
       470 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0006:
         
     | 
| 
       471 
     | 
    
         
            -
                                pass
         
     | 
| 
       472 
     | 
    
         
            -
             
     | 
| 
       473 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF000A:
         
     | 
| 
       474 
     | 
    
         
            -
                                pass
         
     | 
| 
       475 
     | 
    
         
            -
             
     | 
| 
       476 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0013:
         
     | 
| 
       477 
     | 
    
         
            -
                                pass
         
     | 
| 
       478 
     | 
    
         
            -
             
     | 
| 
       479 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0014:
         
     | 
| 
       480 
     | 
    
         
            -
                                pass
         
     | 
| 
       481 
     | 
    
         
            -
             
     | 
| 
       482 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0019:
         
     | 
| 
       483 
     | 
    
         
            -
                                pass
         
     | 
| 
       484 
     | 
    
         
            -
             
     | 
| 
       485 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0025:
         
     | 
| 
       486 
     | 
    
         
            -
                                pass
         
     | 
| 
       487 
     | 
    
         
            -
             
     | 
| 
       488 
     | 
    
         
            -
                            elif extension_signature == 0xBEEF0026:
         
     | 
| 
       489 
     | 
    
         
            -
                                pass
         
     | 
| 
       490 
     | 
    
         
            -
             
     | 
| 
       491 
     | 
    
         
            -
                            else:
         
     | 
| 
       492 
     | 
    
         
            -
                                log.debug(
         
     | 
| 
       493 
     | 
    
         
            -
                                    "Got unsupported beef extension signature 0x%08x from item %r", extension_signature, entry
         
     | 
| 
       494 
     | 
    
         
            -
                                )
         
     | 
| 
       495 
     | 
    
         
            -
                                pass
         
     | 
| 
       496 
     | 
    
         
            -
             
     | 
| 
       497 
     | 
    
         
            -
                            if ext is None:
         
     | 
| 
       498 
     | 
    
         
            -
                                ext = EXTENSION_BLOCK
         
     | 
| 
       499 
     | 
    
         
            -
                                log.debug("Unimplemented extension signature 0x%08x from item %r", extension_signature, entry)
         
     | 
| 
       500 
     | 
    
         
            -
             
     | 
| 
       501 
     | 
    
         
            -
                            ext = ext(extension_buf)
         
     | 
| 
       502 
     | 
    
         
            -
             
     | 
| 
       503 
     | 
    
         
            -
                            entry.extensions.append(ext)
         
     | 
| 
       504 
     | 
    
         
            -
                            extension_offset += extension_size
         
     | 
| 
       505 
     | 
    
         
            -
             
     | 
| 
       506 
     | 
    
         
            -
                    parent = entry
         
     | 
| 
       507 
     | 
    
         
            -
                    yield entry
         
     | 
| 
       508 
     | 
    
         
            -
             
     | 
| 
       509 
     | 
    
         
            -
                    offset += size
         
     | 
| 
       510 
     | 
    
         
            -
             
     | 
| 
       511 
     | 
    
         
            -
             
     | 
| 
       512 
257 
     | 
    
         
             
            class SHITEM:
         
     | 
| 
       513 
258 
     | 
    
         
             
                STRUCT = None
         
     | 
| 
       514 
259 
     | 
    
         | 
| 
         @@ -521,43 +266,43 @@ class SHITEM: 
     | 
|
| 
       521 
266 
     | 
    
         
             
                    self.parent = None
         
     | 
| 
       522 
267 
     | 
    
         
             
                    self.extensions = []
         
     | 
| 
       523 
268 
     | 
    
         | 
| 
      
 269 
     | 
    
         
            +
                def __repr__(self) -> str:
         
     | 
| 
      
 270 
     | 
    
         
            +
                    return f"<{self.__class__.__name__}>"
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
       524 
272 
     | 
    
         
             
                @property
         
     | 
| 
       525 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 273 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       526 
274 
     | 
    
         
             
                    return f"<SHITEM 0x{self.size:x}>"
         
     | 
| 
       527 
275 
     | 
    
         | 
| 
       528 
276 
     | 
    
         
             
                @property
         
     | 
| 
       529 
     | 
    
         
            -
                def creation_time(self):
         
     | 
| 
      
 277 
     | 
    
         
            +
                def creation_time(self) -> None:
         
     | 
| 
       530 
278 
     | 
    
         
             
                    return None
         
     | 
| 
       531 
279 
     | 
    
         | 
| 
       532 
280 
     | 
    
         
             
                @property
         
     | 
| 
       533 
     | 
    
         
            -
                def modification_time(self):
         
     | 
| 
      
 281 
     | 
    
         
            +
                def modification_time(self) -> None:
         
     | 
| 
       534 
282 
     | 
    
         
             
                    return None
         
     | 
| 
       535 
283 
     | 
    
         | 
| 
       536 
284 
     | 
    
         
             
                @property
         
     | 
| 
       537 
     | 
    
         
            -
                def access_time(self):
         
     | 
| 
      
 285 
     | 
    
         
            +
                def access_time(self) -> None:
         
     | 
| 
       538 
286 
     | 
    
         
             
                    return None
         
     | 
| 
       539 
287 
     | 
    
         | 
| 
       540 
288 
     | 
    
         
             
                @property
         
     | 
| 
       541 
     | 
    
         
            -
                def file_size(self):
         
     | 
| 
      
 289 
     | 
    
         
            +
                def file_size(self) -> None:
         
     | 
| 
       542 
290 
     | 
    
         
             
                    return None
         
     | 
| 
       543 
291 
     | 
    
         | 
| 
       544 
292 
     | 
    
         
             
                @property
         
     | 
| 
       545 
     | 
    
         
            -
                def file_reference(self):
         
     | 
| 
      
 293 
     | 
    
         
            +
                def file_reference(self) -> None:
         
     | 
| 
       546 
294 
     | 
    
         
             
                    return None
         
     | 
| 
       547 
295 
     | 
    
         | 
| 
       548 
     | 
    
         
            -
                def extension(self, cls):
         
     | 
| 
      
 296 
     | 
    
         
            +
                def extension(self, cls: Any) -> Any | None:
         
     | 
| 
       549 
297 
     | 
    
         
             
                    for ext in self.extensions:
         
     | 
| 
       550 
298 
     | 
    
         
             
                        if isinstance(ext, cls):
         
     | 
| 
       551 
299 
     | 
    
         
             
                            return ext
         
     | 
| 
       552 
300 
     | 
    
         
             
                    return None
         
     | 
| 
       553 
301 
     | 
    
         | 
| 
       554 
     | 
    
         
            -
                def __repr__(self):
         
     | 
| 
       555 
     | 
    
         
            -
                    return f"<{self.__class__.__name__}>"
         
     | 
| 
       556 
     | 
    
         
            -
             
     | 
| 
       557 
302 
     | 
    
         | 
| 
       558 
303 
     | 
    
         
             
            class UNKNOWN(SHITEM):
         
     | 
| 
       559 
304 
     | 
    
         
             
                @property
         
     | 
| 
       560 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 305 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       561 
306 
     | 
    
         
             
                    type_number = hex(self.type) if self.type else self.type
         
     | 
| 
       562 
307 
     | 
    
         
             
                    return f"<UNKNOWN size=0x{self.size:04x} type={type_number}>"
         
     | 
| 
       563 
308 
     | 
    
         | 
| 
         @@ -573,7 +318,7 @@ class UNKNOWN0(SHITEM): 
     | 
|
| 
       573 
318 
     | 
    
         
             
                        self.guid = uuid.UUID(bytes_le=fh.read(16))
         
     | 
| 
       574 
319 
     | 
    
         | 
| 
       575 
320 
     | 
    
         
             
                @property
         
     | 
| 
       576 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 321 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       577 
322 
     | 
    
         
             
                    if self.guid:
         
     | 
| 
       578 
323 
     | 
    
         
             
                        GUID_name = shell_folder_ids.DESCRIPTIONS.get(str(self.guid))
         
     | 
| 
       579 
324 
     | 
    
         
             
                        return GUID_name or f"<UNKNOWN0: {{{self.guid}}}>"
         
     | 
| 
         @@ -585,11 +330,11 @@ class UNKNOWN1(SHITEM): 
     | 
|
| 
       585 
330 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_UNKNOWN1
         
     | 
| 
       586 
331 
     | 
    
         | 
| 
       587 
332 
     | 
    
         
             
                @property
         
     | 
| 
       588 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 333 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       589 
334 
     | 
    
         
             
                    return f"<UNKNOWN1 0x{self.size:x}>"
         
     | 
| 
       590 
335 
     | 
    
         | 
| 
       591 
336 
     | 
    
         | 
| 
       592 
     | 
    
         
            -
            class ROOT_FOLDER(SHITEM): 
     | 
| 
      
 337 
     | 
    
         
            +
            class ROOT_FOLDER(SHITEM):
         
     | 
| 
       593 
338 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_ROOT_FOLDER
         
     | 
| 
       594 
339 
     | 
    
         | 
| 
       595 
340 
     | 
    
         
             
                def __init__(self, fh):
         
     | 
| 
         @@ -601,7 +346,7 @@ class ROOT_FOLDER(SHITEM):  # noqa 
     | 
|
| 
       601 
346 
     | 
    
         
             
                        self.extension = None
         
     | 
| 
       602 
347 
     | 
    
         | 
| 
       603 
348 
     | 
    
         
             
                @property
         
     | 
| 
       604 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 349 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       605 
350 
     | 
    
         
             
                    GUID_name = shell_folder_ids.DESCRIPTIONS.get(str(self.guid))
         
     | 
| 
       606 
351 
     | 
    
         
             
                    return GUID_name or f"{{{self.item.folder_id.name}: {self.guid}}}"
         
     | 
| 
       607 
352 
     | 
    
         | 
| 
         @@ -616,12 +361,12 @@ class VOLUME(SHITEM): 
     | 
|
| 
       616 
361 
     | 
    
         
             
                    if self.type == 0x2E:
         
     | 
| 
       617 
362 
     | 
    
         
             
                        self.identifier = uuid.UUID(bytes_le=buf[4:20].tobytes())
         
     | 
| 
       618 
363 
     | 
    
         
             
                    else:
         
     | 
| 
       619 
     | 
    
         
            -
                        self.volume_name = self.fh.read(20).rstrip(b"\x00").decode()
         
     | 
| 
      
 364 
     | 
    
         
            +
                        self.volume_name = self.fh.read(20).rstrip(b"\x00").decode(errors="surrogateescape")
         
     | 
| 
       620 
365 
     | 
    
         
             
                        if self.size >= 41:
         
     | 
| 
       621 
366 
     | 
    
         
             
                            self.identifier = uuid.UUID(bytes_le=buf[25:41].tobytes())
         
     | 
| 
       622 
367 
     | 
    
         | 
| 
       623 
368 
     | 
    
         
             
                @property
         
     | 
| 
       624 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 369 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       625 
370 
     | 
    
         
             
                    if self.volume_name:
         
     | 
| 
       626 
371 
     | 
    
         
             
                        return self.volume_name
         
     | 
| 
       627 
372 
     | 
    
         
             
                    if self.identifier:
         
     | 
| 
         @@ -630,7 +375,7 @@ class VOLUME(SHITEM): 
     | 
|
| 
       630 
375 
     | 
    
         
             
                    return f"<VOLUME 0x{self.type:02x}>"
         
     | 
| 
       631 
376 
     | 
    
         | 
| 
       632 
377 
     | 
    
         | 
| 
       633 
     | 
    
         
            -
            class FILE_ENTRY(SHITEM): 
     | 
| 
      
 378 
     | 
    
         
            +
            class FILE_ENTRY(SHITEM):
         
     | 
| 
       634 
379 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_FILE_ENTRY
         
     | 
| 
       635 
380 
     | 
    
         | 
| 
       636 
381 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
         @@ -644,7 +389,7 @@ class FILE_ENTRY(SHITEM):  # noqa 
     | 
|
| 
       644 
389 
     | 
    
         
             
                        self.primary_name = c_bag.wchar[None](self.fh)
         
     | 
| 
       645 
390 
     | 
    
         
             
                        self.is_unicode = True
         
     | 
| 
       646 
391 
     | 
    
         
             
                    else:
         
     | 
| 
       647 
     | 
    
         
            -
                        self.primary_name = c_bag.char[None](self.fh).decode()
         
     | 
| 
      
 392 
     | 
    
         
            +
                        self.primary_name = c_bag.char[None](self.fh).decode(errors="surrogateescape")
         
     | 
| 
       648 
393 
     | 
    
         
             
                        self.is_unicode = False
         
     | 
| 
       649 
394 
     | 
    
         | 
| 
       650 
395 
     | 
    
         
             
                    if self.fh.tell() % 2:
         
     | 
| 
         @@ -659,17 +404,17 @@ class FILE_ENTRY(SHITEM):  # noqa 
     | 
|
| 
       659 
404 
     | 
    
         
             
                        if self.is_unicode:
         
     | 
| 
       660 
405 
     | 
    
         
             
                            self.secondary_name = c_bag.wchar[None](self.fh)
         
     | 
| 
       661 
406 
     | 
    
         
             
                        else:
         
     | 
| 
       662 
     | 
    
         
            -
                            self.secondary_name = c_bag.char[None](self.fh).decode()
         
     | 
| 
      
 407 
     | 
    
         
            +
                            self.secondary_name = c_bag.char[None](self.fh).decode(errors="surrogateescape")
         
     | 
| 
       663 
408 
     | 
    
         | 
| 
       664 
409 
     | 
    
         
             
                @property
         
     | 
| 
       665 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 410 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       666 
411 
     | 
    
         
             
                    ext = self.extension(EXTENSION_BLOCK_BEEF0004)
         
     | 
| 
       667 
412 
     | 
    
         
             
                    if ext and ext.long_name:
         
     | 
| 
       668 
413 
     | 
    
         
             
                        return ext.long_name
         
     | 
| 
       669 
414 
     | 
    
         
             
                    return self.primary_name
         
     | 
| 
       670 
415 
     | 
    
         | 
| 
       671 
416 
     | 
    
         
             
                @property
         
     | 
| 
       672 
     | 
    
         
            -
                def modification_time(self):
         
     | 
| 
      
 417 
     | 
    
         
            +
                def modification_time(self) -> datetime | None:
         
     | 
| 
       673 
418 
     | 
    
         
             
                    ts = self.item.modification_time
         
     | 
| 
       674 
419 
     | 
    
         
             
                    if ts > 0:
         
     | 
| 
       675 
420 
     | 
    
         
             
                        return dostimestamp(ts, swap=True)
         
     | 
| 
         @@ -691,15 +436,15 @@ class NETWORK(SHITEM): 
     | 
|
| 
       691 
436 
     | 
    
         
             
                        self.comments = c_bag.char[None](self.fh)
         
     | 
| 
       692 
437 
     | 
    
         | 
| 
       693 
438 
     | 
    
         
             
                @property
         
     | 
| 
       694 
     | 
    
         
            -
                def name(self):
         
     | 
| 
       695 
     | 
    
         
            -
                    return self.item.location.decode()
         
     | 
| 
      
 439 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
      
 440 
     | 
    
         
            +
                    return self.item.location.decode(errors="surrogateescape")
         
     | 
| 
       696 
441 
     | 
    
         | 
| 
       697 
442 
     | 
    
         | 
| 
       698 
     | 
    
         
            -
            class COMPRESSED_FOLDER(SHITEM): 
     | 
| 
      
 443 
     | 
    
         
            +
            class COMPRESSED_FOLDER(SHITEM):
         
     | 
| 
       699 
444 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_COMPRESSED_FOLDER
         
     | 
| 
       700 
445 
     | 
    
         | 
| 
       701 
446 
     | 
    
         
             
                @property
         
     | 
| 
       702 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 447 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       703 
448 
     | 
    
         
             
                    return "<COMPRESSED_FOLDER>"
         
     | 
| 
       704 
449 
     | 
    
         | 
| 
       705 
450 
     | 
    
         | 
| 
         @@ -714,14 +459,14 @@ class URI(SHITEM): 
     | 
|
| 
       714 
459 
     | 
    
         
             
                        if self.item.flags & 0x80:
         
     | 
| 
       715 
460 
     | 
    
         
             
                            self.uri = c_bag.wchar[None](self.fh)
         
     | 
| 
       716 
461 
     | 
    
         
             
                        else:
         
     | 
| 
       717 
     | 
    
         
            -
                            self.uri = c_bag.char[None](self.fh).decode()
         
     | 
| 
      
 462 
     | 
    
         
            +
                            self.uri = c_bag.char[None](self.fh).decode(errors="surrogateescape")
         
     | 
| 
       718 
463 
     | 
    
         | 
| 
       719 
464 
     | 
    
         
             
                @property
         
     | 
| 
       720 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 465 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       721 
466 
     | 
    
         
             
                    return self.uri or "<URI>"
         
     | 
| 
       722 
467 
     | 
    
         | 
| 
       723 
468 
     | 
    
         | 
| 
       724 
     | 
    
         
            -
            class CONTROL_PANEL(SHITEM): 
     | 
| 
      
 469 
     | 
    
         
            +
            class CONTROL_PANEL(SHITEM):
         
     | 
| 
       725 
470 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_CONTROL_PANEL
         
     | 
| 
       726 
471 
     | 
    
         | 
| 
       727 
472 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
         @@ -729,12 +474,12 @@ class CONTROL_PANEL(SHITEM):  # noqa 
     | 
|
| 
       729 
474 
     | 
    
         
             
                    self.guid = uuid.UUID(bytes_le=self.item.guid)
         
     | 
| 
       730 
475 
     | 
    
         | 
| 
       731 
476 
     | 
    
         
             
                @property
         
     | 
| 
       732 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 477 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       733 
478 
     | 
    
         
             
                    GUID_name = shell_folder_ids.DESCRIPTIONS.get(str(self.guid))
         
     | 
| 
       734 
479 
     | 
    
         
             
                    return GUID_name or f"<CONTROL_PANEL {self.guid}>"
         
     | 
| 
       735 
480 
     | 
    
         | 
| 
       736 
481 
     | 
    
         | 
| 
       737 
     | 
    
         
            -
            class CONTROL_PANEL_CATEGORY(SHITEM): 
     | 
| 
      
 482 
     | 
    
         
            +
            class CONTROL_PANEL_CATEGORY(SHITEM):
         
     | 
| 
       738 
483 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_CONTROL_PANEL_CATEGORY
         
     | 
| 
       739 
484 
     | 
    
         
             
                CATEGORIES = {
         
     | 
| 
       740 
485 
     | 
    
         
             
                    0: "All Control Panel Items",
         
     | 
| 
         @@ -752,7 +497,7 @@ class CONTROL_PANEL_CATEGORY(SHITEM):  # noqa 
     | 
|
| 
       752 
497 
     | 
    
         
             
                }
         
     | 
| 
       753 
498 
     | 
    
         | 
| 
       754 
499 
     | 
    
         
             
                @property
         
     | 
| 
       755 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 500 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       756 
501 
     | 
    
         
             
                    categ_str = self.CATEGORIES.get(self.item.category)
         
     | 
| 
       757 
502 
     | 
    
         
             
                    if categ_str:
         
     | 
| 
       758 
503 
     | 
    
         
             
                        return categ_str
         
     | 
| 
         @@ -763,11 +508,11 @@ class CDBURN(SHITEM): 
     | 
|
| 
       763 
508 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_CDBURN
         
     | 
| 
       764 
509 
     | 
    
         | 
| 
       765 
510 
     | 
    
         
             
                @property
         
     | 
| 
       766 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 511 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       767 
512 
     | 
    
         
             
                    return "<CDBURN>"
         
     | 
| 
       768 
513 
     | 
    
         | 
| 
       769 
514 
     | 
    
         | 
| 
       770 
     | 
    
         
            -
            class GAME_FOLDER(SHITEM): 
     | 
| 
      
 515 
     | 
    
         
            +
            class GAME_FOLDER(SHITEM):
         
     | 
| 
       771 
516 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_GAME_FOLDER
         
     | 
| 
       772 
517 
     | 
    
         | 
| 
       773 
518 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
         @@ -775,43 +520,43 @@ class GAME_FOLDER(SHITEM):  # noqa 
     | 
|
| 
       775 
520 
     | 
    
         
             
                    self.guid = uuid.UUID(bytes_le=self.item.identifier)
         
     | 
| 
       776 
521 
     | 
    
         | 
| 
       777 
522 
     | 
    
         
             
                @property
         
     | 
| 
       778 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 523 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       779 
524 
     | 
    
         
             
                    return f"<GAME_FOLDER {{{self.guid}}}>"
         
     | 
| 
       780 
525 
     | 
    
         | 
| 
       781 
526 
     | 
    
         | 
| 
       782 
     | 
    
         
            -
            class CONTROL_PANEL_CPL_FILE(SHITEM): 
     | 
| 
      
 527 
     | 
    
         
            +
            class CONTROL_PANEL_CPL_FILE(SHITEM):
         
     | 
| 
       783 
528 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_CONTROL_PANEL_CPL_FILE
         
     | 
| 
       784 
529 
     | 
    
         | 
| 
       785 
530 
     | 
    
         
             
                @property
         
     | 
| 
       786 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 531 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       787 
532 
     | 
    
         
             
                    return f"<CONTROL_PANEL_CPL_FILE path={self.item.cpl_path} name={self.item.name} comments={self.item.comments}>"
         
     | 
| 
       788 
533 
     | 
    
         | 
| 
       789 
534 
     | 
    
         | 
| 
       790 
     | 
    
         
            -
            class MTP_FILE_ENTRY(SHITEM): 
     | 
| 
      
 535 
     | 
    
         
            +
            class MTP_FILE_ENTRY(SHITEM):
         
     | 
| 
       791 
536 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_MTP_FILE_ENTRY
         
     | 
| 
       792 
537 
     | 
    
         | 
| 
       793 
538 
     | 
    
         
             
                @property
         
     | 
| 
       794 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 539 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       795 
540 
     | 
    
         
             
                    return "<MTP_FILE_ENTRY>"
         
     | 
| 
       796 
541 
     | 
    
         | 
| 
       797 
542 
     | 
    
         
             
                @property
         
     | 
| 
       798 
     | 
    
         
            -
                def creation_time(self):
         
     | 
| 
      
 543 
     | 
    
         
            +
                def creation_time(self) -> datetime:
         
     | 
| 
       799 
544 
     | 
    
         
             
                    return self.item.creation_time
         
     | 
| 
       800 
545 
     | 
    
         | 
| 
       801 
546 
     | 
    
         
             
                @property
         
     | 
| 
       802 
     | 
    
         
            -
                def modification_time(self):
         
     | 
| 
      
 547 
     | 
    
         
            +
                def modification_time(self) -> datetime:
         
     | 
| 
       803 
548 
     | 
    
         
             
                    return self.item.modification_time
         
     | 
| 
       804 
549 
     | 
    
         | 
| 
       805 
550 
     | 
    
         | 
| 
       806 
     | 
    
         
            -
            class MTP_VOLUME(SHITEM): 
     | 
| 
      
 551 
     | 
    
         
            +
            class MTP_VOLUME(SHITEM):
         
     | 
| 
       807 
552 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_MTP_FILE_ENTRY
         
     | 
| 
       808 
553 
     | 
    
         | 
| 
       809 
554 
     | 
    
         
             
                @property
         
     | 
| 
       810 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 555 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       811 
556 
     | 
    
         
             
                    return "<MTP_VOLUME>"
         
     | 
| 
       812 
557 
     | 
    
         | 
| 
       813 
558 
     | 
    
         | 
| 
       814 
     | 
    
         
            -
            class USERS_PROPERTY_VIEW(SHITEM): 
     | 
| 
      
 559 
     | 
    
         
            +
            class USERS_PROPERTY_VIEW(SHITEM):
         
     | 
| 
       815 
560 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_USERS_PROPERTY_VIEW
         
     | 
| 
       816 
561 
     | 
    
         | 
| 
       817 
562 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
         @@ -823,13 +568,13 @@ class USERS_PROPERTY_VIEW(SHITEM):  # noqa 
     | 
|
| 
       823 
568 
     | 
    
         
             
                        self.guid = uuid.UUID(bytes_le=self.item.identifier)
         
     | 
| 
       824 
569 
     | 
    
         | 
| 
       825 
570 
     | 
    
         
             
                @property
         
     | 
| 
       826 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 571 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       827 
572 
     | 
    
         
             
                    # As we don't know how to handle identifier_size other than 16 bytes, we fall back to data_signature
         
     | 
| 
       828 
573 
     | 
    
         
             
                    property_view = self.guid or self.identifier
         
     | 
| 
       829 
574 
     | 
    
         
             
                    return f"<USERS_PROPERTY_VIEW {{{property_view}}}>"
         
     | 
| 
       830 
575 
     | 
    
         | 
| 
       831 
576 
     | 
    
         | 
| 
       832 
     | 
    
         
            -
            class UNKNOWN_0x74(SHITEM): 
     | 
| 
      
 577 
     | 
    
         
            +
            class UNKNOWN_0x74(SHITEM):
         
     | 
| 
       833 
578 
     | 
    
         
             
                STRUCT = c_bag.SHITEM_UNKNOWN_0x74
         
     | 
| 
       834 
579 
     | 
    
         | 
| 
       835 
580 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
         @@ -839,11 +584,11 @@ class UNKNOWN_0x74(SHITEM):  # noqa 
     | 
|
| 
       839 
584 
     | 
    
         
             
                        self.subitem = c_bag.SHITEM_UNKNOWN_0x74_SUBITEM(self.fh)
         
     | 
| 
       840 
585 
     | 
    
         | 
| 
       841 
586 
     | 
    
         
             
                @property
         
     | 
| 
       842 
     | 
    
         
            -
                def name(self):
         
     | 
| 
       843 
     | 
    
         
            -
                    return self.subitem.primary_name.decode() if self.subitem else "<UNKNOWN_0x74>"
         
     | 
| 
      
 587 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
      
 588 
     | 
    
         
            +
                    return self.subitem.primary_name.decode(errors="surrogateescape") if self.subitem else "<UNKNOWN_0x74>"
         
     | 
| 
       844 
589 
     | 
    
         | 
| 
       845 
590 
     | 
    
         
             
                @property
         
     | 
| 
       846 
     | 
    
         
            -
                def modification_time(self):
         
     | 
| 
      
 591 
     | 
    
         
            +
                def modification_time(self) -> datetime | None:
         
     | 
| 
       847 
592 
     | 
    
         
             
                    if self.subitem.modification_time > 0:
         
     | 
| 
       848 
593 
     | 
    
         
             
                        return dostimestamp(self.subitem.modification_time, swap=True) if self.subitem else None
         
     | 
| 
       849 
594 
     | 
    
         
             
                    return None
         
     | 
| 
         @@ -858,38 +603,38 @@ class DELEGATE(SHITEM): 
     | 
|
| 
       858 
603 
     | 
    
         
             
                    self.shell_identifier = uuid.UUID(bytes_le=self.item.shell_identifier)
         
     | 
| 
       859 
604 
     | 
    
         | 
| 
       860 
605 
     | 
    
         
             
                @property
         
     | 
| 
       861 
     | 
    
         
            -
                def name(self):
         
     | 
| 
      
 606 
     | 
    
         
            +
                def name(self) -> str:
         
     | 
| 
       862 
607 
     | 
    
         
             
                    GUID_name = shell_folder_ids.DESCRIPTIONS.get(str(self.shell_identifier))
         
     | 
| 
       863 
608 
     | 
    
         
             
                    return GUID_name if GUID_name else f"{{{self.shell_identifier}}}"
         
     | 
| 
       864 
609 
     | 
    
         | 
| 
       865 
610 
     | 
    
         | 
| 
       866 
     | 
    
         
            -
            class EXTENSION_BLOCK: 
     | 
| 
      
 611 
     | 
    
         
            +
            class EXTENSION_BLOCK:
         
     | 
| 
       867 
612 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
       868 
613 
     | 
    
         
             
                    self.buf = buf
         
     | 
| 
       869 
614 
     | 
    
         
             
                    self.fh = io.BytesIO(buf)
         
     | 
| 
       870 
615 
     | 
    
         
             
                    self.header = c_bag.EXTENSION_BLOCK_HEADER(self.fh)
         
     | 
| 
       871 
616 
     | 
    
         | 
| 
      
 617 
     | 
    
         
            +
                def __repr__(self) -> str:
         
     | 
| 
      
 618 
     | 
    
         
            +
                    return f"<EXTENSION_BLOCK size=0x{self.size:04x} version=0x{self.version:04x} signature=0x{self.signature:08x}>"
         
     | 
| 
      
 619 
     | 
    
         
            +
             
     | 
| 
       872 
620 
     | 
    
         
             
                @property
         
     | 
| 
       873 
     | 
    
         
            -
                def size(self):
         
     | 
| 
      
 621 
     | 
    
         
            +
                def size(self) -> int:
         
     | 
| 
       874 
622 
     | 
    
         
             
                    return self.header.size
         
     | 
| 
       875 
623 
     | 
    
         | 
| 
       876 
624 
     | 
    
         
             
                @property
         
     | 
| 
       877 
     | 
    
         
            -
                def data_size(self):
         
     | 
| 
      
 625 
     | 
    
         
            +
                def data_size(self) -> int:
         
     | 
| 
       878 
626 
     | 
    
         
             
                    return self.size - 8  # minus header
         
     | 
| 
       879 
627 
     | 
    
         | 
| 
       880 
628 
     | 
    
         
             
                @property
         
     | 
| 
       881 
     | 
    
         
            -
                def version(self):
         
     | 
| 
      
 629 
     | 
    
         
            +
                def version(self) -> int:
         
     | 
| 
       882 
630 
     | 
    
         
             
                    return self.header.version
         
     | 
| 
       883 
631 
     | 
    
         | 
| 
       884 
632 
     | 
    
         
             
                @property
         
     | 
| 
       885 
     | 
    
         
            -
                def signature(self):
         
     | 
| 
      
 633 
     | 
    
         
            +
                def signature(self) -> int:
         
     | 
| 
       886 
634 
     | 
    
         
             
                    return self.header.signature
         
     | 
| 
       887 
635 
     | 
    
         | 
| 
       888 
     | 
    
         
            -
                def __repr__(self):
         
     | 
| 
       889 
     | 
    
         
            -
                    return f"<EXTENSION_BLOCK size=0x{self.size:04x} version=0x{self.version:04x} signature=0x{self.signature:08x}>"
         
     | 
| 
       890 
     | 
    
         
            -
             
     | 
| 
       891 
636 
     | 
    
         | 
| 
       892 
     | 
    
         
            -
            class EXTENSION_BLOCK_BEEF0004(EXTENSION_BLOCK): 
     | 
| 
      
 637 
     | 
    
         
            +
            class EXTENSION_BLOCK_BEEF0004(EXTENSION_BLOCK):
         
     | 
| 
       893 
638 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
       894 
639 
     | 
    
         
             
                    super().__init__(buf)
         
     | 
| 
       895 
640 
     | 
    
         
             
                    fh = self.fh
         
     | 
| 
         @@ -923,8 +668,269 @@ class EXTENSION_BLOCK_BEEF0004(EXTENSION_BLOCK):  # noqa 
     | 
|
| 
       923 
668 
     | 
    
         
             
                        self.localized_name = c_bag.wchar[None](fh)
         
     | 
| 
       924 
669 
     | 
    
         | 
| 
       925 
670 
     | 
    
         | 
| 
       926 
     | 
    
         
            -
            class EXTENSION_BLOCK_BEEF0005(EXTENSION_BLOCK): 
     | 
| 
      
 671 
     | 
    
         
            +
            class EXTENSION_BLOCK_BEEF0005(EXTENSION_BLOCK):
         
     | 
| 
       927 
672 
     | 
    
         
             
                def __init__(self, buf):
         
     | 
| 
       928 
673 
     | 
    
         
             
                    super().__init__(buf)
         
     | 
| 
       929 
674 
     | 
    
         
             
                    c_bag.char[16](self.fh)  # GUID?
         
     | 
| 
       930 
675 
     | 
    
         
             
                    self.shell_items = self.fh.read(self.data_size - 18)
         
     | 
| 
      
 676 
     | 
    
         
            +
             
     | 
| 
      
 677 
     | 
    
         
            +
             
     | 
| 
      
 678 
     | 
    
         
            +
            ShellBagRecord = create_extended_descriptor([RegistryRecordDescriptorExtension, UserRecordDescriptorExtension])(
         
     | 
| 
      
 679 
     | 
    
         
            +
                "windows/shellbag",
         
     | 
| 
      
 680 
     | 
    
         
            +
                [
         
     | 
| 
      
 681 
     | 
    
         
            +
                    ("datetime", "ts_mtime"),
         
     | 
| 
      
 682 
     | 
    
         
            +
                    ("datetime", "ts_atime"),
         
     | 
| 
      
 683 
     | 
    
         
            +
                    ("datetime", "ts_btime"),
         
     | 
| 
      
 684 
     | 
    
         
            +
                    ("string", "type"),
         
     | 
| 
      
 685 
     | 
    
         
            +
                    ("path", "path"),
         
     | 
| 
      
 686 
     | 
    
         
            +
                    ("datetime", "regf_mtime"),
         
     | 
| 
      
 687 
     | 
    
         
            +
                ],
         
     | 
| 
      
 688 
     | 
    
         
            +
            )
         
     | 
| 
      
 689 
     | 
    
         
            +
             
     | 
| 
      
 690 
     | 
    
         
            +
             
     | 
| 
      
 691 
     | 
    
         
            +
            class ShellBagsPlugin(Plugin):
         
     | 
| 
      
 692 
     | 
    
         
            +
                """Windows Shellbags plugin."""
         
     | 
| 
      
 693 
     | 
    
         
            +
             
     | 
| 
      
 694 
     | 
    
         
            +
                KEYS = [
         
     | 
| 
      
 695 
     | 
    
         
            +
                    "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell",
         
     | 
| 
      
 696 
     | 
    
         
            +
                    "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\ShellNoRoam",
         
     | 
| 
      
 697 
     | 
    
         
            +
                    "HKEY_CURRENT_USER\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell",
         
     | 
| 
      
 698 
     | 
    
         
            +
                    "HKEY_CURRENT_USER\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\ShellNoRoam",
         
     | 
| 
      
 699 
     | 
    
         
            +
                    "HKEY_CURRENT_USER\\Software\\Classes\\Wow6432Node\\Local Settings\\Software\\Microsoft\\Windows\\Shell",
         
     | 
| 
      
 700 
     | 
    
         
            +
                    "HKEY_CURRENT_USER\\Software\\Classes\\Wow6432Node\\Local Settings\\Software\\Microsoft\\Windows\\ShellNoRoam",
         
     | 
| 
      
 701 
     | 
    
         
            +
                    "HKEY_CURRENT_USER\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU",
         
     | 
| 
      
 702 
     | 
    
         
            +
                ]
         
     | 
| 
      
 703 
     | 
    
         
            +
             
     | 
| 
      
 704 
     | 
    
         
            +
                def __init__(self, target: Target):
         
     | 
| 
      
 705 
     | 
    
         
            +
                    super().__init__(target)
         
     | 
| 
      
 706 
     | 
    
         
            +
                    self.bagkeys: list[RegistryKey] = list(self.target.registry.keys(self.KEYS))
         
     | 
| 
      
 707 
     | 
    
         
            +
             
     | 
| 
      
 708 
     | 
    
         
            +
                def check_compatible(self) -> None:
         
     | 
| 
      
 709 
     | 
    
         
            +
                    if not self.bagkeys:
         
     | 
| 
      
 710 
     | 
    
         
            +
                        raise UnsupportedPluginError("No shellbags found")
         
     | 
| 
      
 711 
     | 
    
         
            +
             
     | 
| 
      
 712 
     | 
    
         
            +
                @export(record=ShellBagRecord)
         
     | 
| 
      
 713 
     | 
    
         
            +
                def shellbags(self) -> Iterator[ShellBagRecord]:
         
     | 
| 
      
 714 
     | 
    
         
            +
                    """Yields Windows Shellbags.
         
     | 
| 
      
 715 
     | 
    
         
            +
             
     | 
| 
      
 716 
     | 
    
         
            +
                    Shellbags are registry keys to improve user experience when using Windows Explorer.
         
     | 
| 
      
 717 
     | 
    
         
            +
                    They contain information such as file and folder creation time and access time.
         
     | 
| 
      
 718 
     | 
    
         
            +
             
     | 
| 
      
 719 
     | 
    
         
            +
                    References:
         
     | 
| 
      
 720 
     | 
    
         
            +
                        - https://github.com/libyal/libfwsi
         
     | 
| 
      
 721 
     | 
    
         
            +
                        - https://www.giac.org/paper/gcfa/9576/windows-shellbag-forensics-in-depth/128522
         
     | 
| 
      
 722 
     | 
    
         
            +
                        - https://www.hackingarticles.in/forensic-investigation-shellbags/
         
     | 
| 
      
 723 
     | 
    
         
            +
                    """
         
     | 
| 
      
 724 
     | 
    
         
            +
                    for regkey in self.bagkeys:
         
     | 
| 
      
 725 
     | 
    
         
            +
                        try:
         
     | 
| 
      
 726 
     | 
    
         
            +
                            yield from self._walk_bags(regkey.subkey("BagMRU"), None)
         
     | 
| 
      
 727 
     | 
    
         
            +
             
     | 
| 
      
 728 
     | 
    
         
            +
                        except RegistryKeyNotFoundError:
         
     | 
| 
      
 729 
     | 
    
         
            +
                            continue
         
     | 
| 
      
 730 
     | 
    
         
            +
             
     | 
| 
      
 731 
     | 
    
         
            +
                        except Exception as e:
         
     | 
| 
      
 732 
     | 
    
         
            +
                            self.target.log.error("Exception while parsing shellbags")
         
     | 
| 
      
 733 
     | 
    
         
            +
                            self.target.log.debug("", exc_info=e)
         
     | 
| 
      
 734 
     | 
    
         
            +
                            continue
         
     | 
| 
      
 735 
     | 
    
         
            +
             
     | 
| 
      
 736 
     | 
    
         
            +
                def _walk_bags(self, key: RegistryKey, path_prefix: str | None) -> Iterator[ShellBagRecord]:
         
     | 
| 
      
 737 
     | 
    
         
            +
                    """Recursively walk shellbags from the given RegistryKey location."""
         
     | 
| 
      
 738 
     | 
    
         
            +
                    path_prefix = [] if path_prefix is None else [path_prefix]
         
     | 
| 
      
 739 
     | 
    
         
            +
                    user = self.target.registry.get_user(key)
         
     | 
| 
      
 740 
     | 
    
         
            +
             
     | 
| 
      
 741 
     | 
    
         
            +
                    for reg_val in key.values():
         
     | 
| 
      
 742 
     | 
    
         
            +
                        name, value = reg_val.name, reg_val.value
         
     | 
| 
      
 743 
     | 
    
         
            +
                        if not name.isdigit():
         
     | 
| 
      
 744 
     | 
    
         
            +
                            continue
         
     | 
| 
      
 745 
     | 
    
         
            +
                        path = None
         
     | 
| 
      
 746 
     | 
    
         
            +
             
     | 
| 
      
 747 
     | 
    
         
            +
                        for item in parse_shell_item_list(value):
         
     | 
| 
      
 748 
     | 
    
         
            +
                            path = "\\".join(path_prefix + [item.name])
         
     | 
| 
      
 749 
     | 
    
         
            +
                            yield ShellBagRecord(
         
     | 
| 
      
 750 
     | 
    
         
            +
                                ts_mtime=item.modification_time,
         
     | 
| 
      
 751 
     | 
    
         
            +
                                ts_atime=item.access_time,
         
     | 
| 
      
 752 
     | 
    
         
            +
                                ts_btime=item.creation_time,
         
     | 
| 
      
 753 
     | 
    
         
            +
                                type=item.__class__.__name__,
         
     | 
| 
      
 754 
     | 
    
         
            +
                                path=windows_path(path),
         
     | 
| 
      
 755 
     | 
    
         
            +
                                regf_mtime=key.ts,
         
     | 
| 
      
 756 
     | 
    
         
            +
                                _key=key,
         
     | 
| 
      
 757 
     | 
    
         
            +
                                _user=user,
         
     | 
| 
      
 758 
     | 
    
         
            +
                                _target=self.target,
         
     | 
| 
      
 759 
     | 
    
         
            +
                            )
         
     | 
| 
      
 760 
     | 
    
         
            +
             
     | 
| 
      
 761 
     | 
    
         
            +
                        yield from self._walk_bags(key.subkey(name), path)
         
     | 
| 
      
 762 
     | 
    
         
            +
             
     | 
| 
      
 763 
     | 
    
         
            +
             
     | 
| 
      
 764 
     | 
    
         
            +
            def parse_shell_item_list(buf: bytes) -> Iterator[SHITEM]:
         
     | 
| 
      
 765 
     | 
    
         
            +
                """Parse a shellbag item from the given bytes."""
         
     | 
| 
      
 766 
     | 
    
         
            +
             
     | 
| 
      
 767 
     | 
    
         
            +
                offset = 0
         
     | 
| 
      
 768 
     | 
    
         
            +
                end = len(buf)
         
     | 
| 
      
 769 
     | 
    
         
            +
                list_buf = memoryview(buf)
         
     | 
| 
      
 770 
     | 
    
         
            +
                parent = None
         
     | 
| 
      
 771 
     | 
    
         
            +
             
     | 
| 
      
 772 
     | 
    
         
            +
                while offset < end:
         
     | 
| 
      
 773 
     | 
    
         
            +
                    size = c_bag.uint16(list_buf[offset : offset + 2])
         
     | 
| 
      
 774 
     | 
    
         
            +
             
     | 
| 
      
 775 
     | 
    
         
            +
                    if size == 0:
         
     | 
| 
      
 776 
     | 
    
         
            +
                        break
         
     | 
| 
      
 777 
     | 
    
         
            +
             
     | 
| 
      
 778 
     | 
    
         
            +
                    item_buf = list_buf[offset : offset + size]
         
     | 
| 
      
 779 
     | 
    
         
            +
             
     | 
| 
      
 780 
     | 
    
         
            +
                    entry = None
         
     | 
| 
      
 781 
     | 
    
         
            +
                    if size >= 8:
         
     | 
| 
      
 782 
     | 
    
         
            +
                        signature = c_bag.uint32(item_buf[4:8])
         
     | 
| 
      
 783 
     | 
    
         
            +
                        if signature == 0x39DE2184:
         
     | 
| 
      
 784 
     | 
    
         
            +
                            entry = CONTROL_PANEL_CATEGORY
         
     | 
| 
      
 785 
     | 
    
         
            +
                        elif signature == 0x4D677541:
         
     | 
| 
      
 786 
     | 
    
         
            +
                            entry = CDBURN
         
     | 
| 
      
 787 
     | 
    
         
            +
                        elif signature == 0x49534647:
         
     | 
| 
      
 788 
     | 
    
         
            +
                            entry = GAME_FOLDER
         
     | 
| 
      
 789 
     | 
    
         
            +
                        elif signature == 0xFFFFFF38:
         
     | 
| 
      
 790 
     | 
    
         
            +
                            entry = CONTROL_PANEL_CPL_FILE
         
     | 
| 
      
 791 
     | 
    
         
            +
             
     | 
| 
      
 792 
     | 
    
         
            +
                    if size >= 10 and not entry:
         
     | 
| 
      
 793 
     | 
    
         
            +
                        signature = c_bag.uint32(item_buf[6:10])
         
     | 
| 
      
 794 
     | 
    
         
            +
                        if signature == 0x07192006:
         
     | 
| 
      
 795 
     | 
    
         
            +
                            entry = MTP_FILE_ENTRY
         
     | 
| 
      
 796 
     | 
    
         
            +
                        elif signature == 0x10312005:
         
     | 
| 
      
 797 
     | 
    
         
            +
                            entry = MTP_VOLUME
         
     | 
| 
      
 798 
     | 
    
         
            +
                        elif signature in (0x10141981, 0x23A3DFD5, 0x23FEBBEE, 0x3B93AFBB, 0xBEEBEE00):
         
     | 
| 
      
 799 
     | 
    
         
            +
                            entry = USERS_PROPERTY_VIEW
         
     | 
| 
      
 800 
     | 
    
         
            +
                        elif signature == 0x46534643:
         
     | 
| 
      
 801 
     | 
    
         
            +
                            entry = UNKNOWN_0x74
         
     | 
| 
      
 802 
     | 
    
         
            +
             
     | 
| 
      
 803 
     | 
    
         
            +
                    if size >= 38 and not entry:
         
     | 
| 
      
 804 
     | 
    
         
            +
                        if item_buf[size - 32 : size] == DELEGATE_ITEM_IDENTIFIER:
         
     | 
| 
      
 805 
     | 
    
         
            +
                            entry = DELEGATE
         
     | 
| 
      
 806 
     | 
    
         
            +
             
     | 
| 
      
 807 
     | 
    
         
            +
                    if size >= 3 and not entry:
         
     | 
| 
      
 808 
     | 
    
         
            +
                        class_type = item_buf[2]
         
     | 
| 
      
 809 
     | 
    
         
            +
                        mask_type = class_type & 0x70
         
     | 
| 
      
 810 
     | 
    
         
            +
             
     | 
| 
      
 811 
     | 
    
         
            +
                        if mask_type == 0x00:
         
     | 
| 
      
 812 
     | 
    
         
            +
                            if class_type == 0x00:
         
     | 
| 
      
 813 
     | 
    
         
            +
                                entry = UNKNOWN0
         
     | 
| 
      
 814 
     | 
    
         
            +
                            elif class_type == 0x01:
         
     | 
| 
      
 815 
     | 
    
         
            +
                                entry = UNKNOWN1
         
     | 
| 
      
 816 
     | 
    
         
            +
             
     | 
| 
      
 817 
     | 
    
         
            +
                        elif mask_type == 0x10:
         
     | 
| 
      
 818 
     | 
    
         
            +
                            if class_type == 0x1F:
         
     | 
| 
      
 819 
     | 
    
         
            +
                                entry = ROOT_FOLDER
         
     | 
| 
      
 820 
     | 
    
         
            +
             
     | 
| 
      
 821 
     | 
    
         
            +
                        elif mask_type == 0x20:
         
     | 
| 
      
 822 
     | 
    
         
            +
                            if class_type in (0x23, 0x25, 0x29, 0x2A, 0x2E, 0x2F):
         
     | 
| 
      
 823 
     | 
    
         
            +
                                entry = VOLUME
         
     | 
| 
      
 824 
     | 
    
         
            +
             
     | 
| 
      
 825 
     | 
    
         
            +
                        elif mask_type == 0x30:
         
     | 
| 
      
 826 
     | 
    
         
            +
                            if class_type in (0x30, 0x31, 0x32, 0x35, 0x36, 0xB1):
         
     | 
| 
      
 827 
     | 
    
         
            +
                                entry = FILE_ENTRY
         
     | 
| 
      
 828 
     | 
    
         
            +
             
     | 
| 
      
 829 
     | 
    
         
            +
                        elif mask_type == 0x40:
         
     | 
| 
      
 830 
     | 
    
         
            +
                            if class_type in (0x41, 0x42, 0x46, 0x47, 0x4C, 0xC3):
         
     | 
| 
      
 831 
     | 
    
         
            +
                                entry = NETWORK
         
     | 
| 
      
 832 
     | 
    
         
            +
             
     | 
| 
      
 833 
     | 
    
         
            +
                        elif mask_type == 0x50:
         
     | 
| 
      
 834 
     | 
    
         
            +
                            if class_type == 0x52:
         
     | 
| 
      
 835 
     | 
    
         
            +
                                entry = COMPRESSED_FOLDER
         
     | 
| 
      
 836 
     | 
    
         
            +
             
     | 
| 
      
 837 
     | 
    
         
            +
                        elif mask_type == 0x60:
         
     | 
| 
      
 838 
     | 
    
         
            +
                            if class_type == 0x61:
         
     | 
| 
      
 839 
     | 
    
         
            +
                                entry = URI
         
     | 
| 
      
 840 
     | 
    
         
            +
             
     | 
| 
      
 841 
     | 
    
         
            +
                        elif mask_type == 0x70:
         
     | 
| 
      
 842 
     | 
    
         
            +
                            if class_type == 0x71:
         
     | 
| 
      
 843 
     | 
    
         
            +
                                entry = CONTROL_PANEL
         
     | 
| 
      
 844 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 845 
     | 
    
         
            +
                            if not entry:
         
     | 
| 
      
 846 
     | 
    
         
            +
                                log.debug("No supported shell item found for size 0x%04x and type 0x%02x", size, class_type)
         
     | 
| 
      
 847 
     | 
    
         
            +
                                entry = UNKNOWN
         
     | 
| 
      
 848 
     | 
    
         
            +
             
     | 
| 
      
 849 
     | 
    
         
            +
                    if not entry:
         
     | 
| 
      
 850 
     | 
    
         
            +
                        log.debug("No supported shell item found for size 0x%04x", size)
         
     | 
| 
      
 851 
     | 
    
         
            +
                        entry = UNKNOWN
         
     | 
| 
      
 852 
     | 
    
         
            +
             
     | 
| 
      
 853 
     | 
    
         
            +
                    entry = entry(item_buf)
         
     | 
| 
      
 854 
     | 
    
         
            +
                    entry.parent = parent
         
     | 
| 
      
 855 
     | 
    
         
            +
             
     | 
| 
      
 856 
     | 
    
         
            +
                    first_extension_block_offset = c_bag.uint16(item_buf[-2:])
         
     | 
| 
      
 857 
     | 
    
         
            +
                    if 4 <= first_extension_block_offset < size - 2:
         
     | 
| 
      
 858 
     | 
    
         
            +
                        extension_offset = first_extension_block_offset
         
     | 
| 
      
 859 
     | 
    
         
            +
                        while extension_offset < size - 2:
         
     | 
| 
      
 860 
     | 
    
         
            +
                            extension_size = c_bag.uint16(item_buf[extension_offset : extension_offset + 2])
         
     | 
| 
      
 861 
     | 
    
         
            +
             
     | 
| 
      
 862 
     | 
    
         
            +
                            if extension_size == 0:
         
     | 
| 
      
 863 
     | 
    
         
            +
                                break
         
     | 
| 
      
 864 
     | 
    
         
            +
             
     | 
| 
      
 865 
     | 
    
         
            +
                            if extension_size > size - extension_offset:
         
     | 
| 
      
 866 
     | 
    
         
            +
                                log.debug(
         
     | 
| 
      
 867 
     | 
    
         
            +
                                    "Extension size exceeds item size: 0x%04x > 0x%04x - 0x%04x",
         
     | 
| 
      
 868 
     | 
    
         
            +
                                    extension_size,
         
     | 
| 
      
 869 
     | 
    
         
            +
                                    size,
         
     | 
| 
      
 870 
     | 
    
         
            +
                                    extension_offset,
         
     | 
| 
      
 871 
     | 
    
         
            +
                                )
         
     | 
| 
      
 872 
     | 
    
         
            +
                                break  # Extension size too large
         
     | 
| 
      
 873 
     | 
    
         
            +
             
     | 
| 
      
 874 
     | 
    
         
            +
                            extension_buf = item_buf[extension_offset : extension_offset + extension_size]
         
     | 
| 
      
 875 
     | 
    
         
            +
                            extension_signature = c_bag.uint32(extension_buf[4:8])
         
     | 
| 
      
 876 
     | 
    
         
            +
             
     | 
| 
      
 877 
     | 
    
         
            +
                            ext = None
         
     | 
| 
      
 878 
     | 
    
         
            +
             
     | 
| 
      
 879 
     | 
    
         
            +
                            if extension_signature >> 16 != 0xBEEF:
         
     | 
| 
      
 880 
     | 
    
         
            +
                                log.debug("Got unsupported extension signature 0x%08x from item %r", extension_signature, entry)
         
     | 
| 
      
 881 
     | 
    
         
            +
                                pass  # Unsupported
         
     | 
| 
      
 882 
     | 
    
         
            +
             
     | 
| 
      
 883 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0000:
         
     | 
| 
      
 884 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 885 
     | 
    
         
            +
             
     | 
| 
      
 886 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0001:
         
     | 
| 
      
 887 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 888 
     | 
    
         
            +
             
     | 
| 
      
 889 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0003:
         
     | 
| 
      
 890 
     | 
    
         
            +
                                ext = EXTENSION_BLOCK_BEEF0004
         
     | 
| 
      
 891 
     | 
    
         
            +
             
     | 
| 
      
 892 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0004:
         
     | 
| 
      
 893 
     | 
    
         
            +
                                ext = EXTENSION_BLOCK_BEEF0004
         
     | 
| 
      
 894 
     | 
    
         
            +
             
     | 
| 
      
 895 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0005:
         
     | 
| 
      
 896 
     | 
    
         
            +
                                ext = EXTENSION_BLOCK_BEEF0005
         
     | 
| 
      
 897 
     | 
    
         
            +
             
     | 
| 
      
 898 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0006:
         
     | 
| 
      
 899 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 900 
     | 
    
         
            +
             
     | 
| 
      
 901 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF000A:
         
     | 
| 
      
 902 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 903 
     | 
    
         
            +
             
     | 
| 
      
 904 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0013:
         
     | 
| 
      
 905 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 906 
     | 
    
         
            +
             
     | 
| 
      
 907 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0014:
         
     | 
| 
      
 908 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 909 
     | 
    
         
            +
             
     | 
| 
      
 910 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0019:
         
     | 
| 
      
 911 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 912 
     | 
    
         
            +
             
     | 
| 
      
 913 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0025:
         
     | 
| 
      
 914 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 915 
     | 
    
         
            +
             
     | 
| 
      
 916 
     | 
    
         
            +
                            elif extension_signature == 0xBEEF0026:
         
     | 
| 
      
 917 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 918 
     | 
    
         
            +
             
     | 
| 
      
 919 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 920 
     | 
    
         
            +
                                log.debug(
         
     | 
| 
      
 921 
     | 
    
         
            +
                                    "Got unsupported beef extension signature 0x%08x from item %r", extension_signature, entry
         
     | 
| 
      
 922 
     | 
    
         
            +
                                )
         
     | 
| 
      
 923 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 924 
     | 
    
         
            +
             
     | 
| 
      
 925 
     | 
    
         
            +
                            if ext is None:
         
     | 
| 
      
 926 
     | 
    
         
            +
                                ext = EXTENSION_BLOCK
         
     | 
| 
      
 927 
     | 
    
         
            +
                                log.debug("Unimplemented extension signature 0x%08x from item %r", extension_signature, entry)
         
     | 
| 
      
 928 
     | 
    
         
            +
             
     | 
| 
      
 929 
     | 
    
         
            +
                            ext = ext(extension_buf)
         
     | 
| 
      
 930 
     | 
    
         
            +
             
     | 
| 
      
 931 
     | 
    
         
            +
                            entry.extensions.append(ext)
         
     | 
| 
      
 932 
     | 
    
         
            +
                            extension_offset += extension_size
         
     | 
| 
      
 933 
     | 
    
         
            +
             
     | 
| 
      
 934 
     | 
    
         
            +
                    parent = entry
         
     | 
| 
      
 935 
     | 
    
         
            +
                    offset += size
         
     | 
| 
      
 936 
     | 
    
         
            +
                    yield entry
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Metadata-Version: 2.1
         
     | 
| 
       2 
2 
     | 
    
         
             
            Name: dissect.target
         
     | 
| 
       3 
     | 
    
         
            -
            Version: 3.20. 
     | 
| 
      
 3 
     | 
    
         
            +
            Version: 3.20.dev26
         
     | 
| 
       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
         
     | 
| 
         @@ -23,7 +23,7 @@ dissect/target/containers/vmdk.py,sha256=5fQGkJy4esXONXrKLbhpkQDt8Fwx19YENK2mOm7 
     | 
|
| 
       23 
23 
     | 
    
         
             
            dissect/target/data/autocompletion/target_bash_completion.sh,sha256=wrOQ_ED-h8WFcjCmY6n4qKl84tWJv9l8ShFHDfJqJyA,3592
         
     | 
| 
       24 
24 
     | 
    
         
             
            dissect/target/filesystems/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       25 
25 
     | 
    
         
             
            dissect/target/filesystems/ad1.py,sha256=nEPzaaRsb6bL4ItFo0uLdmdLvrmK9BjqHeD3FOp3WQI,2413
         
     | 
| 
       26 
     | 
    
         
            -
            dissect/target/filesystems/btrfs.py,sha256= 
     | 
| 
      
 26 
     | 
    
         
            +
            dissect/target/filesystems/btrfs.py,sha256=TotOs0-VOmgSijERZb1pOrIH_E7B1J_DRKqws8ttQTk,6569
         
     | 
| 
       27 
27 
     | 
    
         
             
            dissect/target/filesystems/cb.py,sha256=6LcoJiwsYu1Han31IUzVpZVDTifhTLTx_gLfNpB_p6k,5329
         
     | 
| 
       28 
28 
     | 
    
         
             
            dissect/target/filesystems/config.py,sha256=GQOtixIIt-Jjtpl3IVqUTujcBFfWaAZeAtvxgNUNetU,11963
         
     | 
| 
       29 
29 
     | 
    
         
             
            dissect/target/filesystems/cpio.py,sha256=ssVCjkAtLn2FqmNxeo6U5boyUdSYFxLWfXpytHYGPqs,641
         
     | 
| 
         @@ -34,7 +34,7 @@ dissect/target/filesystems/fat.py,sha256=ZSw-wS57vo5eIXJndfI1rZkGu_qh-vyioMzCZFZ 
     | 
|
| 
       34 
34 
     | 
    
         
             
            dissect/target/filesystems/ffs.py,sha256=Wu8sS1jjmD0QXXcAaD2h_zzfvinjco8qvj0hErufZ-4,4555
         
     | 
| 
       35 
35 
     | 
    
         
             
            dissect/target/filesystems/itunes.py,sha256=w2lcWv6jlBPm84tsGZehxKBMXXyuW3KlmwVTF4ssQec,6395
         
     | 
| 
       36 
36 
     | 
    
         
             
            dissect/target/filesystems/jffs.py,sha256=Ceqa5Em2pepnXMH_XZFmSNjQyWPo1uWTthBFSMWfKRo,3926
         
     | 
| 
       37 
     | 
    
         
            -
            dissect/target/filesystems/ntfs.py,sha256= 
     | 
| 
      
 37 
     | 
    
         
            +
            dissect/target/filesystems/ntfs.py,sha256=Losf35q9aLm-YdwVllT5so99s-GqTF1ZXMbLX0PUNC0,7624
         
     | 
| 
       38 
38 
     | 
    
         
             
            dissect/target/filesystems/overlay.py,sha256=d0BNZcVd3SzBcM1SZO5nX2FrEYcdtVH34BPJQ6Oh4x8,4753
         
     | 
| 
       39 
39 
     | 
    
         
             
            dissect/target/filesystems/smb.py,sha256=uxfcOWwEoDCw8Qpsa94T5Pn-SKd4WXs4OOrzVVI55d8,6406
         
     | 
| 
       40 
40 
     | 
    
         
             
            dissect/target/filesystems/squashfs.py,sha256=ehzlThXB7n96XUvQnsK5tWLsA9HIxYN-Zxl7aO9D7ts,3921
         
     | 
| 
         @@ -334,7 +334,7 @@ dissect/target/plugins/os/windows/regf/nethist.py,sha256=QHbG9fmZNmjSVhrgqMvMo12 
     | 
|
| 
       334 
334 
     | 
    
         
             
            dissect/target/plugins/os/windows/regf/recentfilecache.py,sha256=goS6ajLIh6ZU-Gq4tupoxBoQCfMDp2qJgg-Nn5qFIsY,1850
         
     | 
| 
       335 
335 
     | 
    
         
             
            dissect/target/plugins/os/windows/regf/regf.py,sha256=D1GrljF-sV8cWIjWJ3zH7k52i1OWD8poEC_PIeZMEis,3419
         
     | 
| 
       336 
336 
     | 
    
         
             
            dissect/target/plugins/os/windows/regf/runkeys.py,sha256=-2HcdnVytzCt1xwgAI8rHDnwk8kwLPWURumvhrGnIHU,4278
         
     | 
| 
       337 
     | 
    
         
            -
            dissect/target/plugins/os/windows/regf/shellbags.py,sha256 
     | 
| 
      
 337 
     | 
    
         
            +
            dissect/target/plugins/os/windows/regf/shellbags.py,sha256=-8WkdplG0FR37XgpCTd4iDdQvvrgtOk9kZY5qLsW5J8,26984
         
     | 
| 
       338 
338 
     | 
    
         
             
            dissect/target/plugins/os/windows/regf/shimcache.py,sha256=TY7GEFnxb8h99q12CzM0SwVlUymi4hFPae3uuM0M6kY,9998
         
     | 
| 
       339 
339 
     | 
    
         
             
            dissect/target/plugins/os/windows/regf/trusteddocs.py,sha256=3yvpBDM-Asg0rvGN2TwALGRm9DYogG6TxRau9D6FBbw,3700
         
     | 
| 
       340 
340 
     | 
    
         
             
            dissect/target/plugins/os/windows/regf/usb.py,sha256=nSAHB4Cdd0wF2C1EK_XYOfWCyqOgTZCLfDhuSmr7rdM,9709
         
     | 
| 
         @@ -368,10 +368,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z 
     | 
|
| 
       368 
368 
     | 
    
         
             
            dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
         
     | 
| 
       369 
369 
     | 
    
         
             
            dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
         
     | 
| 
       370 
370 
     | 
    
         
             
            dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
         
     | 
| 
       371 
     | 
    
         
            -
            dissect.target-3.20. 
     | 
| 
       372 
     | 
    
         
            -
            dissect.target-3.20. 
     | 
| 
       373 
     | 
    
         
            -
            dissect.target-3.20. 
     | 
| 
       374 
     | 
    
         
            -
            dissect.target-3.20. 
     | 
| 
       375 
     | 
    
         
            -
            dissect.target-3.20. 
     | 
| 
       376 
     | 
    
         
            -
            dissect.target-3.20. 
     | 
| 
       377 
     | 
    
         
            -
            dissect.target-3.20. 
     | 
| 
      
 371 
     | 
    
         
            +
            dissect.target-3.20.dev26.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
         
     | 
| 
      
 372 
     | 
    
         
            +
            dissect.target-3.20.dev26.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
         
     | 
| 
      
 373 
     | 
    
         
            +
            dissect.target-3.20.dev26.dist-info/METADATA,sha256=9ta9bS0OqAMhf6vc8zDqGxpXSkY-YRJMAHWRucXo3f8,12897
         
     | 
| 
      
 374 
     | 
    
         
            +
            dissect.target-3.20.dev26.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
         
     | 
| 
      
 375 
     | 
    
         
            +
            dissect.target-3.20.dev26.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
         
     | 
| 
      
 376 
     | 
    
         
            +
            dissect.target-3.20.dev26.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
         
     | 
| 
      
 377 
     | 
    
         
            +
            dissect.target-3.20.dev26.dist-info/RECORD,,
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
    
        {dissect.target-3.20.dev23.dist-info → dissect.target-3.20.dev26.dist-info}/entry_points.txt
    RENAMED
    
    | 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |