diff --git a/scripts/artifacts/windowsSearchDb.py b/scripts/artifacts/windowsSearchDb.py new file mode 100644 index 0000000..a35476f --- /dev/null +++ b/scripts/artifacts/windowsSearchDb.py @@ -0,0 +1,205 @@ +"""Windows Search index (Windows.db, Windows 11) parser for DLEAPP. + +Author: @AlexisBrignoni, Claude. +Inspired by the Velociraptor exchange Windows.Search work. This is the SQLite +sibling of windowsSearch.py: Windows 11 (22H2 and later) replaced the ESE +Windows.edb search index with a SQLite database, Windows.db. + +Windows.db keeps indexed-item properties as (WorkId, ColumnId, Value) triples in +a SystemIndex__PropertyStore table, with a SystemIndex__PropertyStore_ +Metadata table mapping each ColumnId to its System.* property name. This artifact +pivots the triples back to one row per indexed item. +""" + +import sqlite3 +import struct +from datetime import datetime, timedelta, timezone + +from scripts.ilapfuncs import artifact_processor, logfunc + +_WINDOWS_DB = "windows.db" + +# System.* property names surfaced, resolved to their ColumnId per database +# through the metadata table (so a ColumnId that differs between images is fine). +_GATHER = "System.Search.GatherTime" +_MODIFIED = "System.DateModified" +_CREATED = "System.DateCreated" +_ACCESSED = "System.DateAccessed" +_NAME = "System.ItemNameDisplay" +_PATH = "System.ItemPathDisplay" +_URL = "System.ItemUrl" +_TYPE = "System.ItemTypeText" +_KIND = "System.KindText" +_SIZE = "System.Size" +_WANTED = (_GATHER, _MODIFIED, _CREATED, _ACCESSED, _NAME, _PATH, _URL, + _TYPE, _KIND, _SIZE) + +__artifacts_v2__ = { + "windowsSearchDb": { + "name": "Windows 11 Search Index", + "description": "Items indexed by Windows Search from the Windows 11 Windows.db " + "index, with the item path, name, type, size and the gather, " + "modified, created and accessed times the index recorded.", + "author": "@AlexisBrignoni, Claude", + "creation_date": "2026-09-16", + "last_update_date": "2026-09-16", + "requirements": "none", + "category": "Windows", + "notes": "Rows from the SystemIndex__PropertyStore table in Windows.db, the " + "Windows 11 (22H2 and later) Windows Search index, read from the file " + "named in Source File and opened read only. Windows.db keeps each " + "indexed item's properties as (WorkId, ColumnId, Value) rows; the " + "SystemIndex__PropertyStore_Metadata table maps each ColumnId to " + "its System.* property name, and this artifact pivots the rows back " + "to one row per item, keyed by Work ID. Item Name, Item Path and Item " + "URL are the System_ItemNameDisplay, System_ItemPathDisplay and " + "System_ItemUrl properties as stored; Item Path is the display path " + "and Item URL is the stored locator. Gather Time, Date Modified, Date " + "Created and Date Accessed (UTC) are Windows FILETIMEs from the " + "System_Search_GatherTime, System_DateModified, System_DateCreated " + "and System_DateAccessed properties; Gather Time is the time the " + "Windows Search indexer recorded for the item and the other three are " + "the file system times the index stored. Size (bytes) is System_Size, " + "blank for folders and other items the index stored no size for. Type " + "and Kind are System_ItemTypeText and System_KindText as stored, blank " + "where the index holds none. An indexed entry records that Windows " + "Search gathered the item at Gather Time; it does not by itself " + "establish that a user opened the item, and the index can retain an " + "entry after the item is removed from disk. This is the SQLite Windows " + "11 counterpart of the Windows Search Index artifact, which reads the " + "older ESE Windows.edb; the two do not appear together on one system. " + "The property names are read from the index's own metadata table in " + "the file. Format: libyal esedb-kb / Windows Search notes on the " + "Windows.db schema, https://github.com/libyal/esedb-kb/blob/main/" + "documentation/Windows%20Search.asciidoc", + "paths": ("*/[Ss]earch/[Dd]ata/[Aa]pplications/[Ww]indows/" + "[Ww]indows.[Dd][Bb]",), + "output_types": ["standard"], + "artifact_icon": "search", + "sample_data": { + "pc_mus_001_win11": "Windows 11 22H2 build 22621 | 2272 rows", + }, + }, +} + + +def _filetime(value): + if isinstance(value, (bytes, bytearray)) and len(value) == 8: + value = struct.unpack("