Rebuild RDP session screenshots from the client-side bitmap cache.
This repository is vibecoded. It was built largely through AI-assisted, prompt-driven development. Treat it accordingly: review the code before relying on it, expect rough edges, and verify results against ground truth for any forensic or evidentiary use.
When a Windows machine connects out over RDP, the client keeps a persistent
bitmap cache on disk — a grab-bag of 64×64-pixel tiles the server sent, stored
so they never have to be transmitted twice. Each tile is keyed by a 64-bit hash
of its contents and written into bcache*.bmc / cache????.bin files under the
user profile:
C:\Users\<user>\AppData\Local\Microsoft\Terminal Server Client\Cache\
The screen those tiles once formed is gone; only the shards remain. For a forensic analyst that pile of shards is evidence — it can hold window titles, file names, icons and partial screen contents from an RDP session that left no other trace on the machine. The catch is that tiles are stored in cache-eviction order, not screen order, so putting the picture back together has always been "like solving a jigsaw puzzle".
RDPhoenix decodes every cached tile, measures where its edges could join another tile, correlates the runs that genuinely sat next to each other, and reassembles them into readable screenshots — automatically where it can, and on an interactive canvas where it needs a human.
A single desktop application (rdphoenix, built on eframe/egui) with:
- Tile pool — every tile recovered from the cache, deduplicated, with filters for placed / non-square / duplicate tiles. Extraction runs on a background thread behind a progress screen, so the window is up and responsive from the first second.
- Auto-stitch — one button. Matches every tile against its neighbours by pixel-edge continuity, keeps only mutually-best joins, and drops each reconstructed 2-D region onto its own canvas screen for you to check and extend. Runs on a worker thread with a modal progress bar (matching edges → assembling regions).
- Manual canvas — an infinite grid you place tiles on by hand. Arm a tile
in the pool, click a cell. Right-click to remove.
Escto disarm. - Candidate suggestions — hover an empty cell next to a placed tile and the right-hand panel ranks the remaining tiles by how well their touching border pixels match, best first.
- Multiple screens — reconstruct several distinct desktop states side by side, each with its own free-text notes; add and close them as you go. The tab strip scrolls horizontally, so dozens of auto-stitched screens never crowd out the canvas.
- PNG export — write the occupied area of the active screen to a file.
The reconstruction engine lives in the rdphoenix library and the app drives it
directly. A few headless sub-commands remain for pipeline verification.
Requires a Rust toolchain and, for the windowed app, a working display. There are no system library dependencies.
git clone https://github.com/<you>/RDPhoenix
cd RDPhoenix
cargo build --release
./target/release/rdphoenix# Pick the cache directory with a folder dialog:
rdphoenix
# ...or point straight at it:
rdphoenix --source "/mnt/evidence/Users/jdoe/AppData/Local/Microsoft/Terminal Server Client/Cache"Then:
- Wait for the pool to load — it scans
--sourcerecursively for.bmc/.binfiles, skipping zero-byte ones. - Click ⚙ Auto-stitch. Review the screens it creates.
- Refine on the canvas — drag more tiles in from the pool, use the candidate panel to fill gaps, remove wrong guesses with right-click.
- Export current screen as PNG… when a screen looks right.
| Flag | Purpose |
|---|---|
--source DIR |
Cache directory (skips the folder picker). |
--verbose |
Per-tile progress while extracting. |
--dry-run |
Extract, build the pool, print a tile/duplicate summary, no window. |
--verify-ranking LEFT,MIDDLE,RIGHT |
Given three genuinely adjacent tiles, hide the middle one and report where the candidate ranker places the true answer. No window. |
.bmc / .bin containers
│ cache::extract_tiles – opcode-faithful RDP bitmap-cache RLE decoder,
│ ported from ANSSI-FR/bmc-tools
▼
decoded 64×64 tiles (RGBA)
│
│ similarity::seam_score – for a candidate join between two tiles,
│ extrapolate each tile's image one pixel past
│ its own edge and measure how far off it lands
│ from the other tile's edge line. Near-zero =
│ a genuine continuation; flat, featureless
│ seams report "can't tell".
▼
auto::reconstruct (greedy 2-D mosaic solve)
│ 1. score all four ways each nearby pair of tiles could touch
│ 2. keep each tile's single best partner per direction
│ 3. trust a join only when it is *mutually* best and under threshold
│ 4. union-find the trusted joins into regions, walk each from a
│ corner assigning (col, row)
▼
regions of ≥ 4 tiles, laid out in 2-D
▼
GUI: one canvas screen per region · manual placement · candidate
suggestions (same seam_score) · PNG export
Both the automatic pass and the interactive candidate panel use one metric,
similarity::seam_score. It replaces the older colour-count / standard-deviation
proxy: aggregate edge statistics match far too many unrelated tiles, whereas
genuinely adjacent RDP tiles are cut from the same framebuffer and the image —
gradient and all — runs straight across the seam.
The acceptance threshold and the cache-order search window are constants at the
top of src/auto.rs. They may need adjusting against a heavily
RGB565-compressed cache, where colour banding widens the seam error.
RDPhoenix stands on the shoulders of prior work:
- bmc-tools (ANSSI-FR) — the RDP Bitmap Cache container format and decoder, ported here opcode for opcode.
- rdpieces — the original idea of correlating tiles by their edges to reassemble screenshots. RDPhoenix keeps the goal and swaps the edge-statistics heuristic for direct pixel-continuity matching.
- RdpCacheStitcher (BSI) — the human-in-the-loop canvas with ranked tile suggestions, and the mutual-best edge-matching used for the automatic pass.
Background reading: Analyzing and Extracting Bitmap Cache Files from RDP Sessions.
MIT — see LICENSE.

0 comments
log in to comment.