# ese-parser
[](https://crates.io/crates/ese-parser)
[](https://docs.rs/ese-parser)
[](LICENSE)
**Pure-Rust** parser for the Microsoft Extensible Storage Engine (ESE / "Jet Blue") database format. Read-only, forensic-focused, **no C-library FFI** — everything is in-tree Rust.
ESE is the on-disk B-tree Windows uses for:
- `ntds.dit` — Active Directory
- `WebCacheV*.dat` — Edge / IE browsing history
- `Windows.edb` — Search index
- Legacy Exchange `Mail.dat`
- Event Tracing Logs (some flavors)
Part of the [icedracon](https://github.com/icedracon) forensics / offensive-AD ecosystem.
## Status
**`0.1.0`** — skeleton. Header validation + random-access page reads with parsed page-header fields. B-tree walk, catalog decode, and row iteration are on the roadmap for v0.2.
## What v0.1 does
- **`EseFile::open(path)`** — read + validate the 668-byte database header (magic `0x89ABCDEF`, format-version, format-revision, page-size, file-type, backup log-generation numbers so a caller can check DB consistency).
- **`EseFile::page(page_number)`** — random-access read of a specific page. Returns a [`RawPage`] with parsed header fields: page number, previous/next sibling in the B-tree chain, father data page, object ID, available data size, tag count, page flags (leaf / root / parent / long-value / etc.).
- Full page bytes are retained on the [`RawPage`] so a downstream B-tree walker can decode tags on top.
## What v0.1 does *not* do (roadmap)
- **B-tree walk** — root → branch → leaf, following child page pointers. Needed to iterate a table.
- **Catalog decode** — the `MSysObjects` table lists every user table + its column definitions (ATTs → ATTx numeric IDs, column offsets, long-value / multi-value flags).
- **Row / tag decode** — each leaf page has N tag entries pointing at record bytes; each record needs column-defined slicing + long-value chunk reassembly.
- **Encryption** — Windows database encryption (per-page XOR with a table key) is not v0.1.
- **Recovery** — dirty-shutdown recovery from transaction logs is out of scope; use Microsoft's own `esentutl /p /d /r` to bring a dirty DB to consistent state before feeding it to this crate.
Once these land, [`ntds-parse`](https://crates.io/crates/ntds-parse) v0.3 will consume `ese-parser` as its `EseBackend`.
## Usage
```rust,no_run
use ese_parser::{EseFile, page_flag};
let mut db = EseFile::open("ntds.dit")?;
println!(
"ESE format v{}.{}, {}-byte pages, file-type {}",
db.format_version(), db.format_revision(), db.page_size(), db.file_type()
);
// Walk pages 2..100 (page 0 = header, page 1 = shadow header) looking for leaf pages
for pn in 2..100u32 {
let page = db.page(pn)?;
if page.is_leaf() {
println!("page {}: leaf, {} tags, next={}, prev={}",
page.page_number, page.available_page_tag,
page.next_page, page.previous_page);
}
}
# Ok::<_, ese_parser::Error>(())
```
## Verification
- Header offsets validated against [libesedb's ESE spec doc](https://github.com/libyal/libesedb/blob/main/documentation/Extensible%20Storage%20Engine%20(ESE)%20Database%20File%20(EDB)%20format.asciidoc).
- Page header layout matches Joachim Metz's reverse-engineering notes.
- Format-version + page-size accepted values match what libesedb + Windows itself produce for `ntds.dit`, `Windows.edb`, `WebCacheV*.dat`.
## Related icedracon crates
- [`ntds-parse`](https://crates.io/crates/ntds-parse) — NTDS.dit crypto + attribute decoders (will consume `ese-parser` in v0.3)
- [`lsass-parse`](https://crates.io/crates/lsass-parse) — LSASS minidump sibling (different file format, same DFIR / offensive-security scope)
## License
MIT © 2026 [zevs](https://github.com/icedracon)