Task 129: .DB File Format
Task 129: .DB File Format
1. List of Properties of the .DB File Format (Thumbs.db) Intrinsic to Its File System
The .DB file format, specifically referring to Thumbs.db as used in Microsoft Windows for thumbnail caching, is based on the OLE Compound File format (also known as Microsoft Structured Storage). This format is intrinsic to the Windows file system for caching thumbnails in folders containing images, videos, or other media. The properties listed below are derived from the file's binary structure, including its header and organizational elements, which define its behavior within the file system.
- File Signature (Magic Number): The 8-byte identifier at offset 0, typically 0xD0 0xCF 0x11 0xE0 0xA1 0xB1 0x1A 0xE1, confirming it as an OLE Compound File.
- CLSID: A 16-byte class identifier at offset 8, often all zeros for Thumbs.db files.
- Minor Version: A 2-byte value at offset 24, indicating the minor version of the format (e.g., 0x003E).
- Major Version: A 2-byte value at offset 26, indicating the major version (e.g., 0x0003 or 0x0004).
- Byte Order: A 2-byte value at offset 28, typically 0xFFFE for little-endian.
- Sector Shift: A 2-byte value at offset 30, defining the sector size (e.g., 9 for 512-byte sectors).
- Mini Sector Shift: A 2-byte value at offset 32, defining the mini sector size (e.g., 6 for 64-byte sectors).
- Reserved Fields: 6 bytes at offset 34, set to zero.
- Number of Directory Sectors: A 4-byte value at offset 40, typically zero for major version 3.
- Number of FAT Sectors: A 4-byte value at offset 44, indicating the count of File Allocation Table sectors.
- First Directory Sector Location: A 4-byte value at offset 48, pointing to the starting sector of the directory.
- Transaction Signature Number: A 4-byte value at offset 52, used for transaction management.
- Mini Stream Cutoff Size: A 4-byte value at offset 56, typically 0x00001000 (4096 bytes).
- First Mini FAT Sector Location: A 4-byte value at offset 60, pointing to the start of the mini FAT.
- Number of Mini FAT Sectors: A 4-byte value at offset 64, indicating the count of mini FAT sectors.
- First DIFAT Sector Location: A 4-byte value at offset 68, pointing to the double-indirect FAT.
- Number of DIFAT Sectors: A 4-byte value at offset 72, indicating the count of DIFAT sectors.
- DIFAT Array: 436 bytes at offset 76, containing the first 109 FAT sector locations.
- Hidden Attribute: The file is marked as hidden within the file system.
- System Attribute: The file is designated as a system file.
- Stream Structure: Contains a "Catalog" stream (in Windows XP format) with metadata and thumbnail streams named numerically (e.g., "021" representing ID 120 in reverse).
- Thumbnail Formats: Embedded thumbnails stored as JPEG, PNG, or nonstandard RGBA JPEG.
2. Two Direct Download Links for .DB Files
The following are direct download links to sample Thumbs.db files from publicly accessible directories:
3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .DB File Analysis
The following is an embeddable HTML snippet with JavaScript suitable for a Ghost blog post. It enables users to drag and drop a .DB (Thumbs.db) file, parses the OLE header, and displays the properties listed in section 1 on the screen.
4. Python Class for .DB File Handling
The following Python class can open, decode, read, write, and print the properties of a .DB (Thumbs.db) file to the console.
import struct
import os
class DBFileHandler:
def __init__(self, filepath):
self.filepath = filepath
self.properties = {}
def read_and_decode(self):
with open(self.filepath, 'rb') as f:
header = f.read(512)
self.properties = {
'File Signature': ' '.join(f'{b:02X}' for b in header[0:8]),
'CLSID': ' '.join(f'{b:02X}' for b in header[8:24]),
'Minor Version': struct.unpack_from('<H', header, 24)[0],
'Major Version': struct.unpack_from('<H', header, 26)[0],
'Byte Order': struct.unpack_from('<H', header, 28)[0],
'Sector Shift': struct.unpack_from('<H', header, 30)[0],
'Mini Sector Shift': struct.unpack_from('<H', header, 32)[0],
'Reserved Fields': struct.unpack_from('<Q', header, 34)[0], # 6 bytes as long
'Number of Directory Sectors': struct.unpack_from('<I', header, 40)[0],
'Number of FAT Sectors': struct.unpack_from('<I', header, 44)[0],
'First Directory Sector Location': struct.unpack_from('<I', header, 48)[0],
'Transaction Signature Number': struct.unpack_from('<I', header, 52)[0],
'Mini Stream Cutoff Size': struct.unpack_from('<I', header, 56)[0],
'First Mini FAT Sector Location': struct.unpack_from('<I', header, 60)[0],
'Number of Mini FAT Sectors': struct.unpack_from('<I', header, 64)[0],
'First DIFAT Sector Location': struct.unpack_from('<I', header, 68)[0],
'Number of DIFAT Sectors': struct.unpack_from('<I', header, 72)[0],
# Additional file system properties
'Hidden Attribute': bool(os.stat(self.filepath).st_file_attributes & 0x02),
'System Attribute': bool(os.stat(self.filepath).st_file_attributes & 0x04),
}
def print_properties(self):
for key, value in self.properties.items():
print(f"{key}: {value}")
def write(self, new_filepath):
# Simple write: copy existing file and modify a property (e.g., transaction signature)
with open(self.filepath, 'rb') as f_in:
data = f_in.read()
with open(new_filepath, 'wb') as f_out:
f_out.write(data)
# Example modification: set transaction signature to 0
f_out.seek(52)
f_out.write(struct.pack('<I', 0))
# Example usage:
# handler = DBFileHandler('path/to/Thumbs.db')
# handler.read_and_decode()
# handler.print_properties()
# handler.write('path/to/new.db')
5. Java Class for .DB File Handling
The following Java class can open, decode, read, write, and print the properties of a .DB (Thumbs.db) file to the console.
import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
public class DBFileHandler {
private String filepath;
private ByteBuffer header;
private File file;
public DBFileHandler(String filepath) {
this.filepath = filepath;
this.file = new File(filepath);
}
public void readAndDecode() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filepath, "r")) {
header = ByteBuffer.allocate(512).order(ByteOrder.LITTLE_ENDIAN);
raf.getChannel().read(header);
header.rewind();
}
}
public void printProperties() throws IOException {
if (header == null) readAndDecode();
header.rewind();
System.out.print("File Signature: ");
for (int i = 0; i < 8; i++) System.out.print(String.format("%02X ", header.get()));
System.out.println();
System.out.print("CLSID: ");
for (int i = 0; i < 16; i++) System.out.print(String.format("%02X ", header.get()));
System.out.println();
System.out.println("Minor Version: " + header.getShort(24));
System.out.println("Major Version: " + header.getShort(26));
System.out.println("Byte Order: " + header.getShort(28));
System.out.println("Sector Shift: " + header.getShort(30));
System.out.println("Mini Sector Shift: " + header.getShort(32));
System.out.println("Reserved Fields: " + header.getLong(34));
System.out.println("Number of Directory Sectors: " + header.getInt(40));
System.out.println("Number of FAT Sectors: " + header.getInt(44));
System.out.println("First Directory Sector Location: " + header.getInt(48));
System.out.println("Transaction Signature Number: " + header.getInt(52));
System.out.println("Mini Stream Cutoff Size: " + header.getInt(56));
System.out.println("First Mini FAT Sector Location: " + header.getInt(60));
System.out.println("Number of Mini FAT Sectors: " + header.getInt(64));
System.out.println("First DIFAT Sector Location: " + header.getInt(68));
System.out.println("Number of DIFAT Sectors: " + header.getInt(72));
System.out.println("Hidden Attribute: " + file.isHidden());
// System attribute not directly accessible in Java; assume based on context
System.out.println("System Attribute: Assumed (platform dependent)");
}
public void write(String newFilepath) throws IOException {
try (FileChannel inChannel = new FileInputStream(filepath).getChannel();
FileChannel outChannel = new RandomAccessFile(newFilepath, "rw").getChannel()) {
inChannel.transferTo(0, inChannel.size(), outChannel);
// Example modification: set transaction signature to 0
ByteBuffer buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
buf.putInt(0);
buf.flip();
outChannel.position(52);
outChannel.write(buf);
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// DBFileHandler handler = new DBFileHandler("path/to/Thumbs.db");
// handler.printProperties();
// handler.write("path/to/new.db");
// }
}
6. JavaScript Class for .DB File Handling
The following JavaScript class (for Node.js) can open, decode, read, write, and print the properties of a .DB (Thumbs.db) file to the console.
const fs = require('fs');
class DBFileHandler {
constructor(filepath) {
this.filepath = filepath;
this.properties = {};
}
readAndDecode() {
const buffer = fs.readFileSync(this.filepath);
const dv = new DataView(buffer.buffer);
const toHex = (value, bytes) => value.toString(16).padStart(bytes * 2, '0').toUpperCase();
const getBytes = (offset, length) => {
let str = '';
for (let i = 0; i < length; i++) {
str += toHex(dv.getUint8(offset + i), 1) + ' ';
}
return str.trim();
};
this.properties = {
'File Signature': getBytes(0, 8),
'CLSID': getBytes(8, 16),
'Minor Version': dv.getUint16(24, true),
'Major Version': dv.getUint16(26, true),
'Byte Order': dv.getUint16(28, true),
'Sector Shift': dv.getUint16(30, true),
'Mini Sector Shift': dv.getUint16(32, true),
'Reserved Fields': dv.getBigUint64(34, true),
'Number of Directory Sectors': dv.getUint32(40, true),
'Number of FAT Sectors': dv.getUint32(44, true),
'First Directory Sector Location': dv.getUint32(48, true),
'Transaction Signature Number': dv.getUint32(52, true),
'Mini Stream Cutoff Size': dv.getUint32(56, true),
'First Mini FAT Sector Location': dv.getUint32(60, true),
'Number of Mini FAT Sectors': dv.getUint32(64, true),
'First DIFAT Sector Location': dv.getUint32(68, true),
'Number of DIFAT Sectors': dv.getUint32(72, true),
'Hidden Attribute': 'Assumed (file system dependent in Node.js)',
'System Attribute': 'Assumed (file system dependent in Node.js)',
};
}
printProperties() {
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key}: ${value}`);
}
}
write(newFilepath) {
fs.copyFileSync(this.filepath, newFilepath);
const buffer = fs.readFileSync(newFilepath);
const dv = new DataView(buffer.buffer);
dv.setUint32(52, 0, true); // Modify transaction signature
fs.writeFileSync(newFilepath, buffer);
}
}
// Example usage:
// const handler = new DBFileHandler('path/to/Thumbs.db');
// handler.readAndDecode();
// handler.printProperties();
// handler.write('path/to/new.db');
7. C Class for .DB File Handling
The following C code defines a struct-based class-like structure to open, decode, read, write, and print the properties of a .DB (Thumbs.db) file to the console.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
typedef struct {
char* filepath;
uint8_t header[512];
// Properties stored as strings for simplicity
char file_signature[24]; // "XX XX ..." format
// ... other properties can be added similarly
} DBFileHandler;
void init(DBFileHandler* self, char* filepath) {
self->filepath = filepath;
}
void read_and_decode(DBFileHandler* self) {
FILE* f = fopen(self->filepath, "rb");
if (f) {
fread(self->header, 1, 512, f);
fclose(f);
}
}
void print_properties(DBFileHandler* self) {
if (self->header[0] == 0) read_and_decode(self); // Ensure read
printf("File Signature: ");
for (int i = 0; i < 8; i++) printf("%02X ", self->header[i]);
printf("\n");
printf("CLSID: ");
for (int i = 8; i < 24; i++) printf("%02X ", self->header[i]);
printf("\n");
uint16_t* u16 = (uint16_t*)self->header;
printf("Minor Version: %u\n", u16[12]);
printf("Major Version: %u\n", u16[13]);
printf("Byte Order: %u\n", u16[14]);
printf("Sector Shift: %u\n", u16[15]);
printf("Mini Sector Shift: %u\n", u16[16]);
uint64_t* u64 = (uint64_t*)self->header;
printf("Reserved Fields: %llu\n", u64[4] & 0xFFFFFFFFFFFF); // 6 bytes
uint32_t* u32 = (uint32_t*)self->header;
printf("Number of Directory Sectors: %u\n", u32[10]);
printf("Number of FAT Sectors: %u\n", u32[11]);
printf("First Directory Sector Location: %u\n", u32[12]);
printf("Transaction Signature Number: %u\n", u32[13]);
printf("Mini Stream Cutoff Size: %u\n", u32[14]);
printf("First Mini FAT Sector Location: %u\n", u32[15]);
printf("Number of Mini FAT Sectors: %u\n", u32[16]);
printf("First DIFAT Sector Location: %u\n", u32[17]);
printf("Number of DIFAT Sectors: %u\n", u32[18]);
struct stat st;
stat(self->filepath, &st);
printf("Hidden Attribute: %s\n", (st.st_mode & S_IFREG) ? "False" : "True"); // Simplified
printf("System Attribute: Assumed (platform dependent)\n");
}
void write(DBFileHandler* self, char* new_filepath) {
FILE* f_in = fopen(self->filepath, "rb");
FILE* f_out = fopen(new_filepath, "wb");
if (f_in && f_out) {
uint8_t byte;
while (fread(&byte, 1, 1, f_in)) fwrite(&byte, 1, 1, f_out);
// Modify transaction signature to 0
fseek(f_out, 52, SEEK_SET);
uint32_t zero = 0;
fwrite(&zero, sizeof(uint32_t), 1, f_out);
fclose(f_in);
fclose(f_out);
}
}
// Example usage:
// int main() {
// DBFileHandler handler;
// init(&handler, "path/to/Thumbs.db");
// print_properties(&handler);
// write(&handler, "path/to/new.db");
// return 0;
// }