thumbcache_idx.db sits beside the cache files.
It has one row for each picture, giving the picture’s hash and, for each cache file,
the offset of the picture’s entry in it. The libwtcdb document, which this page follows,
lists its purpose as still to be written; the offset arrays make the use clear. All
numbers are little-endian.
File header
Versions 20 and 21 (Windows Vista and 7): 24 bytes
| Offset | Size | Name | Description |
|---|---|---|---|
| 0 | 4 | Signature | IMMM (49 4D 4D 4D). |
| 4 | 4 | Format version | 20 for Windows Vista, 21 for Windows 7. |
| 8 | 4 | Unknown | 0x12 in libwtcdb’s sample. (Vinetto calls this field the cache type.) |
| 12 | 4 | Entries used | How many of the table’s entries are in use. |
| 16 | 4 | Entries in the table | The total, used and unused. |
| 20 | 4 | Unknown | Zero in the sample. |
libwtcdb’s sample header:
49 4D 4D 4D 14 00 00 00 12 00 00 00 81 00 00 00 CA 00 00 00 00 00 00 00
IMMM version 20 unknown 18 129 used 202 in the table
The table starts right after the header and is the number of entries times the entry size (40 bytes for version 20, 32 for version 21).
Windows 8.1, 10 and 11: 28 bytes, then a table of the cache files
The header of version 31 and 32 files (read from real Windows 8.1, 10 and 11 files) is
28 bytes: four bytes (00 30 20 10 in Windows 8.1, 0C 00 30 20 in
Windows 10 and 11), IMMM, the format version as a 64-bit number (the high half
is zero), a word that is 6 in the Windows 8.1 file, 11 in the Windows 10 one and 2 in the
Windows 11 one, the number of entries used (offset 20) and the number of entries in the
table (offset 24). That agrees with libwtcdb’s version 30 header.
Then comes what libwtcdb leaves as a question (“is the rest up to 0x110 part of the header?”): one 32-bit word for each cache file giving that cache file’s size in bytes (0x18, 24, for a file with no entries; 0x100000 for a 1 MiB file; the real Windows 10 cache for 96 pixels is 3 MiB and its word is 0x300000, and every word of the three real index files equals the size of the cache file beside it), then one word for each cache file giving the number of entries it holds (equal to the cache file’s entries that have an identifier in the real files, except for the Windows 11 256 cache, where it is 25 and the file holds more), then one zero word. The table of entries starts after that, at 32 + 8 × the number of cache files: 120 for the 11 files of Windows 8.1 and 144 for the 14 of Windows 10 and 11, and the file is exactly that plus the entry count times the entry size in all three. Vinetto’s “29 unknown words” are these arrays.
Index entries
Each entry is a hash, flags and an array of offsets, one for each cache type of the version, in the order of the cache type table. An offset is a position in that cache file: 0 means not set, and 0xFFFFFFFF means the picture has no entry in that cache file.
| Version | Size | Layout |
|---|---|---|
| 20 | 40 | 0: hash (8); 8: last modified, a FILETIME (8); 16: flags (4); 20: five offsets, for the 32, 96, 256, 1024 and sr files |
| 21 | 32 | 0: hash (8); 8: flags (4); 12: five offsets, as above |
| 30 (Windows 8) | 56 | 0: hash (8); 8: flags (4) and a word (4); 16: nine offsets, for the 16, 32, 48, 96, 256, 1024, sr, wide and exif files; 52: four unknown bytes. Not checked against a real file. |
| 31 (Windows 8.1) | 64 | 0: hash (8); 8: flags (4) and a word (4); 16: eleven offsets, for 16, 32, 48, 96, 256, 1024, 1600, sr, wide, exif and wide_alternate; 60: four zero bytes. Checked on a real file. |
| 32 (Windows 10, 11) | 72 | 0: hash (8); 8: flags (4) and a word (4); 16: fourteen offsets, for 16, 32, 48, 96, 256, 768, 1280, 1920, 2560, sr, wide, exif, wide_alternate and custom_stream. Checked on real files. |
The hash is the same number the cache entries hold as their entry hash. The offsets were checked by following them: in the real Windows Vista, 7, 8.1, 10 and 11 files, all 292 non-empty offsets of the index rows land on a cache entry that carries the row’s hash. The word after the flags in Windows 8 and later rows is sometimes filled; neither dissect.thumbcache nor the other sources know its meaning. How the hash is computed is on the cache files page.
Flags
In versions 20 and 21 the flags’ lowest bit means the entry has no data. libwtcdb lists a number of other bits as set in files and gives no meaning for them, and notes that in Windows 7 the flags seem to say which kind of picture a file holds (instead of the extension that Windows Vista kept). The values it saw:
| Flags | Seen with |
|---|---|
0x08008002 | pictures in the 32, 96 (BMP) and 256 (PNG) files |
0x80000002 | an entry in the 256 file with no data |
0x03003001 | a 96 picture (BMP) |
0x08006202 | a 256 picture (PNG) |
0x08005002, 0x08004802, 0x08006002 | 256 pictures (JPEG) |
Worked examples (libwtcdb’s test data). A version 20 entry:
94 53 B1 8F F9 50 45 5C hash 0x5C4550F98FB15394
00 4A 6E 27 50 63 C5 01 last modified: FILETIME 0x01C56350276E4A00 = 2005-05-28 06:40:36 UTC
01 00 00 00 flags 1: the entry has no data
FF FF FF FF FF FF FF FF offsets for 32 and 96: none
95 9C 12 00 offset for 256: 0x129C95
FF FF FF FF FF FF FF FF offsets for 1024 and sr: none
A version 21 entry:
2B 0D 06 C0 7B 75 1E A1 hash 0xA11E757BC0060D2B
02 00 00 80 flags 0x80000002
FF FF FF FF FF FF FF FF offsets for 32 and 96: none
17 80 67 00 offset for 256: 0x678017
FF FF FF FF FF FF FF FF offsets for 1024 and sr: none
Sources
The libwtcdb document (Joachim Metz, GNU Free Documentation License) for the headers,
entry layouts, flags and worked examples; Vinetto’s thumbIMMM module and the
dissect.thumbcache project (fox-it, AGPL: its structure definitions and its test data,
real Windows Vista, 7, 8.1, 10 and 11 files) for the Windows 8 and later layouts. The
version 20, 21, 31 and 32 layouts were checked against those real files (the offsets by
following them into the cache files, the table positions by the file sizes). Version 30
(Windows 8) had no real file.