Skip to content

Add WindowsThumbcacheFacet for the Windows Explorer thumbnail cache (thumbcache_*.db) - Team huh #692

Description

@seturi

Target release

Target: CASE/UCO 1.5.0

Background

The Windows Explorer thumbnail cache (thumbcache_*.db and
thumbcache_idx.db, stored under
%LocalAppData%\Microsoft\Windows\Explorer\) is a routine and
evidentially important artifact: Windows caches size-bucketed thumbnail
images (16 / 32 / 48 / 96 / 256 / 768 / 1280 / 1920 / 2560 pixels) keyed by
an 8-hex-character ThumbnailCacheID, and — critically — a thumbnail
persists in the cache after the original image file is deleted from the
volume
. The cache therefore recovers visual evidence of images that no
longer exist on disk. Because the cache does not itself store file names
(they resolve through the Windows Search index Windows.edb, which is
frequently unavailable), the ThumbnailCacheID and size bucket are often the
only structured handles an examiner has on the recovered image.

UCO already ships dedicated observable characterizations for comparable OS
artifacts — uco-observable:WindowsPrefetchFacet for Windows Prefetch, and
the SOLVE-IT BrowserCacheData construct for browser caches — but there is
no facet or class anywhere in CASE/UCO (or its bundled extensions) for the
thumbnail cache
. A registry search for "thumbnail" / "thumbcache" / "thumb"
returns zero classes. In current practice examiners are forced to bury the
ThumbnailCacheID, the pixel size bucket, and the derivation of the thumbnail
from a (now-deleted) source image in free-text uco-core:description fields
or ad-hoc Dictionary entries, where they cannot be queried, compared, or
validated. This proposal adds a typed WindowsThumbcacheFacet so those
handles become first-class, queryable evidence, and addresses the missing
"this thumbnail was generated from that source image" relationship.

Related work: uco-observable:WindowsPrefetchFacet (precedent for a
Windows-specific observable facet); SOLVE-IT BrowserCacheData (precedent
for a cache-artifact characterization); the CASE-Examples
multipart_file / raw_data illustrations (embedded-thumbnail modeling,
which is a different case from the OS-level cache).

Requirements

Requirement 1

Define a new WindowsThumbcacheFacet class as a subclass of
uco-observable:Facet.

Properties:

  • thumbnailCacheIdentifier (xsd:string): The ThumbnailCacheID assigned to
    the thumbnail entry within the cache, typically an 8-hex-character value
    that thumbcache_idx.db maps to the cache entry (e.g.
    2ba21a59792ff60a).
  • thumbnailSize (xsd:integer): The pixel size bucket the entry belongs to
    (e.g. 96, 256, 768, 1280), corresponding to the trailing number in the
    thumbcache_<N>.db file name.
  • cacheFileName (xsd:string): The file name of the cache database that
    contains the entry (e.g. thumbcache_256.db).

Requirement 2

Provide a way to link a cached thumbnail to the uco-observable:ObservableObject
it was generated from (the original image/file). Two options are
presented; the proposal recommends Option B as least invasive.

  • Option A — a property on the facet. Add sourceImage
    (range uco-observable:ObservableObject) to WindowsThumbcacheFacet,
    referencing the original image when it can be identified. Omitted when the
    source cannot be resolved (the common case, since the cache stores no file
    name).
  • Option B (recommended) — an observable-relationship vocabulary term.
    Add a value such as Generated_Thumbnail_Of (or Thumbnail_Of) to the
    relationship vocabulary used by
    uco-observable:ObservableRelationship/uco-core:kindOfRelationship.
    The existing vocabulary (Contained_Within, Contains, Created, Created_By,
    Extracted_From, ...) has no term that accurately expresses derivation of a
    thumbnail from a source image: Extracted_From and Created_By both
    misstate the relationship. A new relationship term is additive, reuses the
    existing ObservableRelationship machinery, and does not couple the
    derivation to the thumbcache facet — so it also serves EXIF-embedded
    thumbnails, browser-cache thumbnails, and any other derived-image case.

Both are backward-compatible additions. Modeling the thumbnail-inside-database
containment continues to use the existing Contained_Within term.

Risk / Benefit analysis

Benefits

  • Makes the ThumbnailCacheID, size bucket, and cache file name queryable and
    validatable instead of stranded in free text.
  • Records the highest-value forensic fact — that a thumbnail survives and is
    recoverable after its source image is deleted — in a structured,
    correlatable form (e.g. "list every recovered thumbnail whose original file
    is not present").
  • Parallels existing Windows-artifact modeling (WindowsPrefetchFacet) and
    cache modeling (BrowserCacheData), so it fits established UCO patterns.
  • The recommended relationship term (Option B) is reusable beyond the
    thumbcache, and is additive with no change to existing semantics.

Risks

  • Two ways to express the size bucket exist if cacheFileName and
    thumbnailSize disagree; guidance (and optionally a SHACL shape) should
    note that thumbnailSize must match the number in cacheFileName.
  • Option A couples the source-derivation to the facet; if a general derived-
    image relationship term (Option B) is later added, sourceImage would be
    redundant. This is the reason Option B is recommended.
  • WindowsThumbcacheFacet is deliberately Windows-specific; a future
    cross-platform thumbnail-cache abstraction (e.g. Linux/macOS icon caches)
    may warrant a superclass, but that is out of scope here.

Competencies demonstrated

Competency 1

An examiner works a Windows 11 profile ("Alice") whose Explorer cache
contains thumbcache_96/256/768/1280.db. A 1280-bucket entry
(ThumbnailCacheID 2ba21a59792ff60a) decodes to a JPEG (1280x721) depicting
Mont-Saint-Michel, but the original image file is no longer present on the
volume and Windows.edb is absent, so the file name cannot be recovered. The
examiner needs to (1) record the ThumbnailCacheID, size bucket, and cache
file for the recovered thumbnail in a queryable form, and (2) identify
recovered thumbnails whose source image could not be resolved — the images
that exist only as cached thumbnails.

Competency Question 1.1

Which recovered thumbnails carry a ThumbnailCacheID, and which cache database
(size bucket) does each belong to?

Result 1.1

Every ObservableObject bearing a WindowsThumbcacheFacet, with its
thumbnailCacheIdentifier, thumbnailSize, and cacheFileName — here the
single 1280-bucket thumbnail 2ba21a59792ff60a in thumbcache_1280.db.

Competency Question 1.2

Which cached thumbnails depict images whose original file could not be
recovered (no sourceImage resolved and name not recovered) — i.e. the
thumbnail is the only surviving evidence of a now-deleted image?

Result 1.2

The thumbnail 2ba21a59792ff60a, whose RecoveredObjectFacet reports the
name as not recovered and whose WindowsThumbcacheFacet has no sourceImage.

Draft SPARQL

PREFIX uco-observable: <https://ontology.unifiedcyberontology.org/uco/observable/>
PREFIX uco-core: <https://ontology.unifiedcyberontology.org/uco/core/>
PREFIX proposed: <http://example.org/ontology/proposed/>

SELECT ?thumbnail ?cacheId ?size ?cacheFile
WHERE {
    ?thumbnail a uco-observable:ObservableObject ;
               uco-core:hasFacet ?facet .
    ?facet a proposed:WindowsThumbcacheFacet ;
           proposed:thumbnailCacheIdentifier ?cacheId .
    OPTIONAL { ?facet proposed:thumbnailSize ?size . }
    OPTIONAL { ?facet proposed:cacheFileName ?cacheFile . }
}
ORDER BY ?size ?cacheId

(Competency Question 1.2 is in change_proposals/windows-thumbnail-cache-facet.sparql.)

Example instance data

The example graph is also available as a standalone file at
change_proposals/windows-thumbnail-cache-facet.jsonld for validation and
SPARQL testing. Values are drawn from a Windows 11 Explorer thumbnail cache
(profile "Alice"); the SHA-256 hashValue is a clearly-marked placeholder
(64 zeros).

{
  "@context": {
    "kb": "http://example.org/kb/",
    "proposed": "http://example.org/ontology/proposed/",
    "uco-core": "https://ontology.unifiedcyberontology.org/uco/core/",
    "uco-observable": "https://ontology.unifiedcyberontology.org/uco/observable/",
    "uco-types": "https://ontology.unifiedcyberontology.org/uco/types/",
    "xsd": "http://www.w3.org/2001/XMLSchema#"
  },
  "@graph": [
    {
      "@id": "kb:File-thumbcache-1280-2b25936d-ed8a-467b-8897-a73665549e10",
      "@type": "uco-observable:File",
      "uco-core:name": "thumbcache_1280.db",
      "uco-core:description": [
        "Windows Thumbnail Cache database for the 1280-pixel size bucket, from the Explorer cache of the user 'Alice' on a Windows 11 profile. Cache format signature 'CMMM', cache format version 32."
      ],
      "uco-core:hasFacet": [
        {
          "@id": "kb:FileFacet-4b54f9f1-942b-4140-9834-f37a497853b5",
          "@type": "uco-observable:FileFacet",
          "uco-observable:fileName": "thumbcache_1280.db",
          "uco-observable:filePath": "C:\\Users\\Alice\\AppData\\Local\\Microsoft\\Windows\\Explorer\\thumbcache_1280.db",
          "uco-observable:extension": "db",
          "uco-observable:sizeInBytes": { "@type": "xsd:integer", "@value": "1048576" }
        }
      ]
    },
    {
      "@id": "kb:ObservableObject-thumbnail-3869191d-8d2d-44de-b933-5d36cd7c612d",
      "@type": "uco-observable:ObservableObject",
      "uco-core:name": "2ba21a59792ff60a",
      "uco-core:description": [
        "Recovered thumbnail extracted from thumbcache_1280.db, keyed by ThumbnailCacheID '2ba21a59792ff60a'. Decoded image is a JPEG (1280x721) depicting Mont-Saint-Michel. The original source image file is no longer present on the volume and its filename cannot be recovered from the thumbcache alone."
      ],
      "uco-core:hasFacet": [
        {
          "@id": "kb:RasterPictureFacet-1e779da4-ca97-4863-a262-3aa9102230b9",
          "@type": "uco-observable:RasterPictureFacet",
          "uco-observable:pictureHeight": { "@type": "xsd:integer", "@value": "721" },
          "uco-observable:pictureWidth": { "@type": "xsd:integer", "@value": "1280" },
          "uco-observable:pictureType": "jpg"
        },
        {
          "@id": "kb:ContentDataFacet-44097bec-6615-42e1-9b52-6f31f8c68419",
          "@type": "uco-observable:ContentDataFacet",
          "uco-observable:sizeInBytes": { "@type": "xsd:integer", "@value": "110625" },
          "uco-observable:mimeType": [ "image/jpeg" ],
          "uco-observable:hash": [
            {
              "@id": "kb:Hash-105d6f7b-4f98-4429-9001-350846f56f93",
              "@type": "uco-types:Hash",
              "uco-types:hashMethod": [ "SHA256" ],
              "uco-types:hashValue": {
                "@type": "xsd:hexBinary",
                "@value": "0000000000000000000000000000000000000000000000000000000000000000"
              }
            }
          ]
        },
        {
          "@id": "kb:RecoveredObjectFacet-8e2dcb2c-0408-4071-bf8a-fc4c7176266f",
          "@type": "uco-observable:RecoveredObjectFacet",
          "uco-observable:contentRecoveredStatus": "recovered",
          "uco-observable:nameRecoveredStatus": "Not Recovered"
        },
        {
          "@id": "kb:WindowsThumbcacheFacet-dfb5d59c-b301-4329-82e9-f8a7128a34fc",
          "@type": "proposed:WindowsThumbcacheFacet",
          "proposed:thumbnailCacheIdentifier": "2ba21a59792ff60a",
          "proposed:thumbnailSize": { "@type": "xsd:integer", "@value": "1280" },
          "proposed:cacheFileName": "thumbcache_1280.db"
        }
      ]
    },
    {
      "@id": "kb:ObservableRelationship-42587d73-a925-4cef-9401-ab491773c350",
      "@type": "uco-observable:ObservableRelationship",
      "uco-core:kindOfRelationship": "Contained_Within",
      "uco-core:isDirectional": { "@type": "xsd:boolean", "@value": "true" },
      "uco-core:source": [
        { "@id": "kb:ObservableObject-thumbnail-3869191d-8d2d-44de-b933-5d36cd7c612d" }
      ],
      "uco-core:target": {
        "@id": "kb:File-thumbcache-1280-2b25936d-ed8a-467b-8897-a73665549e10"
      }
    }
  ]
}

I am fine with my examples being transcribed and credited.

Solution suggestion

  • Define new class WindowsThumbcacheFacet as a subclass of
    uco-observable:Facet.
  • Define property thumbnailCacheIdentifier with range xsd:string.
  • Define property thumbnailSize with range xsd:integer.
  • Define property cacheFileName with range xsd:string.
  • For Requirement 2, recommended: add a Generated_Thumbnail_Of
    (or Thumbnail_Of) value to the observable-relationship vocabulary used by
    uco-core:kindOfRelationship. Alternative: add property sourceImage
    (range uco-observable:ObservableObject) to WindowsThumbcacheFacet.
  • Add a SHACL shape for WindowsThumbcacheFacet (property datatypes;
    optional consistency check that thumbnailSize matches the number embedded
    in cacheFileName).
  • Add unit test(s) demonstrating valid usage and at least one failing
    negative fixture.

A prototype extension ontology used for pre-submission validation is at
change_proposals/windows-thumbnail-cache-facet.ttl.

Pre-submission testing

SPARQL query testing

Query Tested Expected results match Notes
CQ 1.1 Yes Yes 1 result: thumbnail 2ba21a59792ff60a, size 1280, thumbcache_1280.db
CQ 1.2 Yes Yes 1 result: thumbnail 2ba21a59792ff60a, name "Not Recovered", no sourceImage

Both queries were executed with rdflib against the example graph loaded
together with the prototype .ttl, and returned exactly the expected single
row each.

Graph validation

case_validate was run in this environment against the example graph with
the prototype ontology supplied as an ontology graph:

$ case_validate --built-version case-1.4.0 --inference rdfs --allow-info \
    --ontology-graph change_proposals/windows-thumbnail-cache-facet.ttl \
    change_proposals/windows-thumbnail-cache-facet.jsonld
Validation Report
Conforms: True
Results (1):
  Severity: sh:Info
  Source Shape: uco-observable:RecoveredObjectFacet-nameRecoveredStatus-in-shape
  Message: Value is not member of the vocabulary RecoveredObjectStatusVocab.

The single sh:Info result is the open-vocabulary suggestion for the
free-text nameRecoveredStatus value "Not Recovered" (the
RecoveredObjectStatusVocab has no negative member); there are no warnings
and no violations. rdfs inference is required so the validator recognizes
WindowsThumbcacheFacet (a subclass of uco-observable:Facet, itself a
subclass of uco-core:Facet) as a valid uco-core:hasFacet value. Without
--inference rdfs the run reports a single sh:Violation on that
subclass-chain check; that is an artifact of the prototype term not being in
the built core ontology, and resolves once the class is added upstream.

Unresolved issues

  • Requirement 2 offers two designs (facet property vs. relationship-vocabulary
    term); the recommendation is the relationship term, but the final choice is
    for the UCO maintainers.
  • Whether a cross-platform icon/thumbnail-cache superclass is warranted
    (macOS/Linux) is left open.

I am fine with my examples being transcribed and credited. — Team huh

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions