← Back to parser

The ESE database format that powers SRUDB.dat

ESE in one paragraph

The Extensible Storage Engine is Microsoft's embedded ISAM database. Each file is a series of fixed-size pages (4 KB or 8 KB) that organise data into B-trees, one per table. Writes go through a transaction log first so the database can recover from crashes mid-flush. The engine is single-process — only the owning service has a handle on the file at a time.

On-disk anatomy

  • Pages — 4 or 8 KB, identified by a 4-byte page number. The first page contains the database header (signature, page size, log signature).
  • B-trees — one per table. A leaf page holds the actual row data; intern pages hold key ranges and child pointers.
  • Catalog — a special B-tree (table id 0) that describes every other table: its name, root page number, and column definitions.
  • Long values — variable-length data too big to fit inline is stored in a separate "long-value" tree, with the row holding a reference.
  • Transaction logs.log files that hold uncommitted writes. The checkpoint file (.chk) records how far the engine has flushed.

Column types you'll meet

ESE has 19 column types. The most common in SRUDB.dat:

Type IDNameEncoding
1Bit1 byte (0/1)
4Long32-bit signed int
7IEEEDouble8-byte float (used for OLE date times)
8DateTime8-byte OLE variant date
11LongBinaryvariable bytes (often XPRESS compressed)
12LongTextvariable UTF-16 / cp1252 text
14UnsignedLong32-bit unsigned int
15LongLong64-bit signed int (often FILETIME)
16GUID16 raw bytes (mixed-endian)

Note that SRUM's TimeStamp column is type 8 (OLE date as f64) while event-style columns like ConnectStartTime are type 15 (FILETIME as i64). A parser must handle both.

Why a fresh tool exists for the web

Existing ESE readers — Joachim Metz' libesedb in C, strozfriedberg/ese_parser in Rust, Velocidex/go-ese in Go — are excellent but desktop/server-targeted.

To run in a browser via WebAssembly:

  • The Rust ese_parser compiles cleanly to wasm32-unknown-unknown.
  • It exposes a Read + Seek API, so a Cursor<Vec<u8>> over the file bytes works without any virtual filesystem layer.
  • Removing the (unused) filepath and nt_comparison features brings the WASM payload to ~160 KB — small enough to ship as a static asset.

That's exactly what powers the SRUM parser on this site.

Recovering from a dirty database

If you copy SRUDB.dat while the SRUM service is writing, the file is "dirty" — the database header marks it as inconsistent. A read-only parser will refuse it or silently skip the pages that need log replay.

The cleanest fix during acquisition is to grab the whole sru\ directory including the .log files. A full ESE library (libesedb, esentutl) can replay the logs against the dirty database and produce a consistent copy.

Related reading

Frequently asked questions

What does ESE stand for?
Extensible Storage Engine. Microsoft also calls it Jet Blue internally. It is an embedded, transactional, ISAM database with B-tree pages.
Where else is ESE used besides SRUM?
Active Directory (NTDS.dit), Microsoft Exchange (mailbox stores), the Edge / Internet Explorer cache (WebCacheV01.dat), Windows Search (Windows.edb), and DHCP.
Can I open SRUDB.dat in Microsoft Access?
No. Access uses Jet Red, a different engine. ESE/Jet Blue has its own on-disk format and requires a dedicated reader like libesedb, ese_parser, or this browser-based tool.
Is the ESE format documented?
Partially. Microsoft open-sourced the ESE engine in 2021. Joachim Metz' libyal project maintains the most complete community reverse-engineered specification.
Why are SRUM rows compressed?
ESE supports per-column XPRESS compression. SRUM uses it on its variable-length payloads (the IdBlob in SruDbIdMapTable, for example) to keep the database small.