The ESE database format that powers SRUDB.dat
5/17/2026
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 —
.logfiles 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 ID | Name | Encoding |
|---|---|---|
| 1 | Bit | 1 byte (0/1) |
| 4 | Long | 32-bit signed int |
| 7 | IEEEDouble | 8-byte float (used for OLE date times) |
| 8 | DateTime | 8-byte OLE variant date |
| 11 | LongBinary | variable bytes (often XPRESS compressed) |
| 12 | LongText | variable UTF-16 / cp1252 text |
| 14 | UnsignedLong | 32-bit unsigned int |
| 15 | LongLong | 64-bit signed int (often FILETIME) |
| 16 | GUID | 16 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_parsercompiles cleanly towasm32-unknown-unknown. - It exposes a
Read + SeekAPI, so aCursor<Vec<u8>>over the file bytes works without any virtual filesystem layer. - Removing the (unused)
filepathandnt_comparisonfeatures 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.