I Built a Windows Debugger From Scratch to Actually See a Stack Smash Happen -

I Built a Windows Debugger From Scratch to Actually See a Stack Smash Happen -

# cybersecurity# cpp# ai# computerscience
I Built a Windows Debugger From Scratch to Actually See a Stack Smash Happen -Fabio Baensch

Why I Built a Windows Debugger From Scratch (Because I Wanted to Understand Crashes, Not...

Why I Built a Windows Debugger From Scratch (Because I Wanted to Understand Crashes, Not Just Catch Them)

A few months ago I got tired of alt-tabbing between WinDbg, a notepad full of scratch notes, and a Python script that tried (badly) to parse register dumps. I wanted something that just showed me what was happening the moment a target crashed — live, without ceremony. So I built expl0itra, a small Windows binary debugger with a Flutter GUI on top of a C++ debug engine.

To be upfront: this is a small side/fun project, not a production tool. I built it mostly to get my hands dirty with the Windows Debug API while I dig deeper into cybersecurity — specifically software development, driver development, and binary exploitation. If you've built something similar or see an obvious way to make this better, I'd genuinely love to hear it in the comments.

What it actually does

expl0itra wraps the Windows Debug API around any .exe you point it at:

  • Live RIP / RBP tracking — register values (and the ASCII content sitting at those addresses) update in real time while the process runs
  • Crash detection — catches second-chance exceptions (Access Violation, Stack Overflow, Heap Corruption, etc.) with full context
  • Memory reader — reads printable ASCII at RIP/RBP, falls back to raw bytes if the address is invalid (e.g. after a stack smash)
  • VirusTotal pre-check — computes a SHA-256 hash of the target and opens it on VirusTotal before you run anything
  • Auto analytics file — on crash, writes a .txt report next to the binary with exception type, register values, memory snapshots, and a timestamp

How it's wired together

The Flutter frontend never touches the Windows Debug API directly — it just spawns expltr_dbg.exe as a child process and talks to it over stdin/stdout:

expl0itra (Flutter GUI)
│
├── startDebugger()          launches expltr_dbg.exe as subprocess
├── stdin  ──────────────►  file path of target binary
└── stdout ◄──────────────  RIP_VAL / RBP_VAL / DBG log lines
                             parsed by regex, displayed live

expltr_dbg.exe (C++ Debug Engine)
│
├── CreateProcessA()         spawns target with DEBUG_ONLY_THIS_PROCESS
├── WaitForDebugEvent()      50ms timeout loop
├── SuspendThread()          snapshots thread context between events
├── GetThreadContext()       reads RIP, RBP
├── ReadProcessMemory()      reads memory at those addresses
├── VirtualQueryEx()         validates address before read
└── fstream analytics        writes .txt report on second-chance exception
Enter fullscreen mode Exit fullscreen mode

The C++ side does the real work: it attaches with DEBUG_ONLY_THIS_PROCESS, polls debug events, and every time it gets a chance it suspends the thread, grabs RIP/RBP via GetThreadContext, and tries to read whatever memory those addresses point to. If the read fails — which happens a lot once you've smashed the stack — it just falls back to showing the raw register bytes instead of crashing the tool itself.

Watching a stack smash happen, live

To sanity-check the tool I threw a classic vulnerable binary at it:

// vuln.c
#include <stdio.h>
#include <string.h>

void vulnerable(char* input) {
    char buf[64];
    strcpy(buf, input);
}

int main() {
    char input[512];
    fgets(input, sizeof(input), stdin);
    vulnerable(input);
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Compiled without a stack canary (gcc vuln.c -o vuln.exe -fno-stack-protector -m64 -O0) and fed a classic overflow payload, expl0itra shows exactly what you'd expect:

RIP: 0x4343434343434343  (CCCCCCCC)
RBP: 0x4242424242424242  (BBBBBBBB)
Enter fullscreen mode Exit fullscreen mode

Seeing the register values overwrite live, instead of reading them post-mortem from a crash dump, made the whole "why does an overflow actually work" concept click in a way that reading about it never quite did.

Known limitations (I'm not hiding these)

  • Targets must be native x64 Windows PE binaries — no .NET, no 32-bit
  • expltr_dbg.exe needs admin privileges for OpenProcess with PROCESS_VM_READ
  • RIP content always shows up as opcode bytes rather than readable text, since it points to code — that's expected, not a bug

Where I'm headed with this

I'm on pwn.college as 0mega_n0d3, and I recently earned the Linux badge there — genuinely one of the things I'm most proud of so far. Right now I'm trying to deepen my binary exploitation skills and connect them to what I already know from reverse engineering, C, and C++. Tools like expl0itra are partly a byproduct of that: building the debugger forces me to actually understand the Windows Debug API instead of just consuming its output through someone else's tool.

Longer term, I want to go further into driver development and lower-level Windows internals — so if you work in that space, or have opinions on how a project like this should evolve (better exception classification? symbol resolution? a proper disassembler view?), I'd really appreciate hearing them.

Repo: expl0itra on GitHub

MIT licensed — do whatever you want with it, just don't hold me liable. 🙂