winbox
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 8 GitHub stars
Code Fail
- exec() — Shell command execution in src/winbox/cli/__init__.py
- exec() — Shell command execution in src/winbox/cli/applocker.py
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Isolated Windows vulnerability-research platform for Kali and AI agents: VM automation, hypervisor debugging, driver/IPC testing, containment, and MCP.
winbox
An isolated Windows vulnerability-research platform for Kali and AI agents.
winbox turns a headless Windows VM (Server Core 2022/2025 or Windows 11) into
an automation, instrumentation, and analysis environment controlled from
Kali. Execute tools, drive a PDB-aware hypervisor debugger, inspect protected
memory, exercise drivers and IPC, change security posture, contain malware,
and collect evidence through one CLI and a 109-tool MCP surface.
Transparent execution is still the shortest path in: typewinbox exec SharpHound.exe -c All -d corp.local and winbox boots the VM,
runs the command, and returns its output. It is now one workflow within the
larger platform rather than the product's whole identity.
Quick Demo
$ winbox setup -y # one-time: builds the VM (~20 min)
$ winbox tools add Rubeus.exe SharpHound.exe # drop in your tools
$ winbox exec Rubeus.exe kerberoast /domain:corp.local
[*] VM is off, starting...
[+] VM ready
[*] Running: Rubeus.exe kerberoast /domain:corp.local
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
...
$ winbox exec --bg --log Seatbelt.exe -group=all # run in background
[+] Job 1 started (PID 4532)
$ winbox shell # SYSTEM shell with full PTY
PS C:\Windows\system32>
Platform capabilities
- MCP server — 109 tools form a bounded, AI-native research control plane
for autonomous agents, covering VM lifecycle, execution, memory, symbols,
debugging, drivers, IPC, defenses, networking, event logs, and evidence
collection. - Hypervisor instrumentation — a persistent QMP/RSP transport, PDB-backed
symbols and Windows structure walks, CR3-aware reads/writes, breakpoints,
watchpoints, stepping, disassembly, exact-binary live decompilation,
predicates, and action traces operate below the guest and across PPL
boundaries. - Target interaction — send IOCTLs, inspect and hold named pipes, manage
services/registry/Defender/HVCI/AppLocker, run tools as SYSTEM or alternate
local users, and keep long-running jobs observable. - Containment and detonation — host-enforced network isolation, full NIC
unplug, packet capture, DNS sinkholing, optional INETSim services, snapshots,
and a fail-closed detonation preflight. See
docs/malware-detonation.md. - Reproducible Windows lab — build and operate Server 2022, Server 2025,
or Windows 11 guests with automatic provisioning, VirtIO-FS staging,
snapshots, VNC, x64dbg, Python, and host-side dependency delivery. - Transparent execution — run
.exefiles like native Kali commands,
including background/logged jobs, one-shot uploads, MSI installation,
ConPTY SYSTEM shells, SSH, and optionalbinfmt_miscdispatch. - Network and domain integration — NAT through Kali, manage DNS/hosts,
join Active Directory domains, or isolate the target without losing the
guest-agent and VirtIO-FS control channels.
Prerequisites
Install on Kali (most are pre-installed):
sudo apt install qemu-system-x86 qemu-utils libvirt-daemon-system virtinst \
libguestfs-tools virtiofsd p7zip-full genisoimage sshpass wget
Required:
qemu-system-x86_64,qemu-img,virsh,virt-install,virt-customize7z(p7zip-full)virtiofsd(at/usr/libexec/virtiofsdor on PATH)/dev/kvm(hardware virtualization must be enabled)mkisofsorgenisoimagewgetdefaultlibvirt network (active)
Optional:
sshpass— auto-auth forwinbox ssh(falls back to manual password entry)virt-manager— required forwinbox vnc(VM display — plain VNC, no clipboard/resize)- Docker — optional;
winbox kdbg ghidra installbuilds the pinned, isolated
headless Ghidra/PyGhidra service used by kdbg's live address-to-pseudocode
bridge. No host Java or Ghidra install is needed. See
docs/kdbg-decomp.md.
Installation
git clone https://github.com/totekuh/winbox.git
cd winbox
pip install -e .
Then build the VM (downloads the eval ISO + VirtIO drivers):
winbox iso download # ~4.7 GB, supports resume
winbox setup -y # builds and provisions the VM
Choosing the guest OS
winbox setup builds Windows Server 2022 by default. Pass --os to build a
different target — Windows Server 2025 or Windows 11 Enterprise (Evaluation):
winbox setup --os server2025 -y # Windows Server 2025 (Core, Evaluation)
winbox setup --os win11 -y # Windows 11 Enterprise (Evaluation)
The choice is build-time and there is one VM at a time — switching OS meanswinbox destroy -y then winbox setup --os <other> -y. Setup records the choice asVM_OS= in ~/.winbox/config, so every later command (status, av, exec, the
MCP server) resolves the same profile as the VM on disk; you can also set that key
yourself to change the default for a bare winbox setup. The right ISO is downloaded
automatically for the selected OS (or pass --iso <path> to use your own).
Notes for Server 2025:
- Same server-minimal build as 2022 (Server Core, no TPM/Secure-Boot gate, 100 MB
ESP layout), but on the Windows 11 24H2 kernel (build 26100).--desktopselects
Desktop Experience, same as 2022. - Because it shares the 24H2 kernel, HVCI/VBS and Defender behavior can differ from
2022 —winbox av statusreports the real Tamper-Protection state. Forkdbg,
use explicit hardware breakpoints when HVCI is on; it blocks software 0xCC bps.
Notes for Win11:
- No TPM / Secure Boot required — setup injects the
LabConfigbypass keys so the
install proceeds on plain UEFI.--desktopis Server-only and rejected for Win11. - Win11 needs a 64 GB system drive and the standard UEFI layout (larger ESP + MSR
partition); setup handles both automatically (the disk is grown to 64 GB and the
Windows partition lands on partition 3). - Defender: Win11 client ships with Tamper Protection on, which normally blocks
the registry-based disable. Setup clears it in the offline registry hive before
first boot so Defender can be turned off during provisioning. This is best-effort
(Defender's cloud component can re-arm it on a networked boot);winbox av status
reports the Tamper-Protection state, andwinbox av disablerefuses honestly rather
than falsely reporting success if TP is still on. - If Microsoft rotates the eval ISO's download link, the auto-download fails loudly;
grab the ISO manually and pass--iso <path>.
Commands
winbox --help groups commands into seven sections:
VM Lifecycle setup provision up down suspend destroy status snapshot restore vnc
Execute eventlogs exec shell ssh jobs msi
Files tools upload iso
Network net dns hosts domain
Target applocker autologin av (bidirectional — flip on to test bypass tools)
Malware Analysis capture detonate sinkhole (detonation lab — capture C2, sinkhole DNS, preflight)
Integrations binfmt kdbg mcp office
Each command supports --help for its own flags and subcommands.
Usage
Executing Commands
winbox exec whoami
winbox exec ipconfig /all
winbox exec Rubeus.exe kerberoast /domain:corp.local
winbox exec --timeout 300 SharpHound.exe -c All # --timeout must come BEFORE the command
winbox exec --user alice --password secret whoami # run as a local Windows user
The VM starts automatically if it's not running.
Background Jobs
Long-running tools can run in the background:
winbox exec --bg Seatbelt.exe -group=all # output buffered in guest agent memory
winbox exec --bg --log Certify.exe find /vulnerable # output redirected to log files (tail -f)
winbox exec --bg --user alice --password secret whoami # background job as a local Windows user
winbox jobs list # check status
winbox jobs output <job-id> # print output
winbox jobs kill <job-id> # kill a running job
With --log, output files are at ~/.winbox/shared/loot/.jobs/<id>.stdout and .stderr.
Interactive Shells
winbox shell # ConPTY reverse shell — runs as SYSTEM, supports terminal resize
winbox ssh # SSH into PowerShell (auto-auth via sshpass)
Managing Tools
Tools placed in the shared directory are available at Z:\tools\ in the VM and automatically on PATH:
winbox tools add Rubeus.exe SharpHound.exe Certify.exe
winbox tools list
winbox tools remove Rubeus.exe
One-shot Uploads and MSI Installs
For files that shouldn't live permanently in the tools dir:
winbox upload payload.exe # stage at Z:\payload.exe
winbox upload payload.exe C:\Windows\Temp\p.exe # also copy into the VM path
winbox msi VMware-tools.msi ADDLOCAL=ALL /norestart # extra args pass through to msiexec
Both stage through the VirtIO-FS share and clean up on failure. winbox msi treats exit code 3010 (reboot required) as success.
Event Logs
Query Windows event logs from inside the VM. Useful right after running a tool to see what Defender / Sysmon / Security audit logged in response.
winbox eventlogs # Security log, last 1h, max 100 (CSV)
winbox eventlogs --since 5m --max 20 # last 5 minutes
winbox eventlogs --log "Microsoft-Windows-Sysmon/Operational" # Sysmon channel
winbox eventlogs --log Security --id 4624 --id 4625 --since 1d
winbox eventlogs --level Error --since 1d --json | jq '.[0]'
winbox eventlogs --since 1h | csvgrep -c Id -m 4624 # pipe into csvkit
Default output is CSV (RFC 4180, fields Time,Log,Level,Id,Provider,Message). --json emits the raw Get-WinEvent JSON. Status messages go to stderr so stdout stays clean for piping. Newlines/tabs in Message are flattened to | so each event is exactly one CSV row. --log is repeatable for multi-channel queries; --id is repeatable and OR'd inside the filter.
Clear channels (destructive, prompts for confirmation unless -y):
winbox eventlogs clear --log Security # one channel
winbox eventlogs clear --log Security --log System -y # multiple
winbox eventlogs clear --all -y # nuke (read-only / system-protected channels are skipped)
Network
# Isolation
winbox net isolate # disconnect VM from network (host-VM channels stay up)
winbox net connect # reconnect VM to network
winbox net status # show link state
# DNS
winbox dns view # show DNS on Kali and VM
winbox dns set 10.10.10.2 # set VM DNS nameserver
winbox dns sync # push Kali's resolv.conf nameservers to VM
# Hosts file
winbox hosts view
winbox hosts add 10.10.10.5 dc01.corp.local
winbox hosts set 10.10.10.5 dc01.corp.local # idempotent — replaces existing entry
winbox hosts delete dc01.corp.local
# Active Directory
winbox domain join corp.local --ns 10.10.10.2 --user admin
# password is prompted interactively
winbox domain leave
VM Lifecycle
winbox up # start or resume
winbox up --reboot # graceful shutdown + start in one command
winbox down # graceful shutdown (needs a running, agent-responsive guest)
winbox down --force # hard power-off (virsh destroy) — works on a paused or wedged VM
winbox suspend # save state to disk (instant resume)
winbox status # state, IP, disk usage, tool/loot counts
winbox destroy -y # delete VM and all storage (clears jobs.json too)
winbox provision # re-run provisioning script
Snapshots
winbox snapshot # list existing snapshots
winbox snapshot pre-attack # create named snapshot (auto-shuts VM down first)
# ... do your thing ...
winbox restore pre-attack # revert to clean state
Office Installation
For testing macro-based payloads, install Office on a Desktop Experience VM:
winbox setup --desktop -y # build VM with Desktop Experience
winbox autologin enable # enable auto-login as Administrator (persistent across reboots)
winbox office # install Word, Excel, PowerPoint with macros enabled
Requires a Microsoft 365 subscription. Macros are enabled (VBAWarnings=1) for Word, Excel, and PowerPoint.
Persistent Autologin
winbox autologin enable # writes all 6 Winlogon+PasswordLess keys Server 2022 needs
winbox autologin status
winbox autologin disable
Unlike the old 3-key approach, this actually survives reboots on Server 2022 (which otherwise silently wipes DefaultPassword on first boot without ForceAutoLogon=1 and the PasswordLess\Device\DevicePasswordLessBuildVersion=0 gate).
AppLocker
Test application whitelisting bypass techniques:
winbox applocker enable # enable AppLocker with default rules (Exe, Script, MSI, Appx)
winbox applocker status # show enforcement status
winbox applocker disable # disable AppLocker, clear policy, reboot
Antivirus (Windows Defender)
winbox av disable # disable Defender completely (reboot required — WinDefend is PPL)
winbox av status # show Defender/AMSI protection status
winbox av enable # re-enable Defender + AMSI (adds QEMU GA/VirtIO-FS exclusions)
Transparent .exe Execution (binfmt_misc)
Register a binfmt_misc handler so .exe files run through winbox automatically:
sudo winbox binfmt enable
./SharpHound.exe -c All # runs via winbox exec
sudo winbox binfmt disable
winbox binfmt status
MCP Server (AI-driven vulnerability research)
The MCP server is the platform's agent control plane, not only a remote shell.
AI agents can manage and contain the VM, run code, instrument live targets from
the hypervisor, resolve PDB symbols, inspect protected address spaces, exercise
drivers and named pipes, change defenses, and retrieve bounded evidence without
constructing one-off transport glue.
Install:
pip install -e '.[mcp]'
Add to Claude Code:
claude mcp add winbox -- winbox mcp
Available tools (109):
User-mode primitives:
| Tool | Description |
|---|---|
exec(command, user?, password?, background?) |
Execute a cmd.exe command, optionally as a local Windows user, in the background, or both |
python(code, user?, password?, background?) |
Execute Python code, optionally as a local Windows user, in the background, or both |
powershell(script, user?, password?, background?) |
Execute encoded PowerShell, optionally as a local Windows user, in the background, or both |
job_result(job_id) |
Retrieve output of a background exec/python/powershell job (non-blocking poll; also visible to winbox jobs) |
ioctl(device, code, input_hex, output_size) |
Send DeviceIoControl to a driver — no ctypes boilerplate |
reg_query(key, value?) |
Query registry key or value |
reg_set(key, value, data, value_type) |
Set registry value (creates key if needed) |
reg_delete(key, value?) |
Delete registry value or entire key tree |
ps(filter?) |
List processes with PID, name, path, memory usage (JSON) |
upload(src, dst?) |
Upload file from Kali to VM via VirtIO-FS (optionally copy to dst inside VM) |
file_copy(src, dst) |
Copy file within the VM (DLL sideloading, staging binaries) |
mem_read(pid, address, length) |
Read memory from a process (enables SeDebugPrivilege, address as hex string, 1MB cap) |
service_start(name) |
Start a Windows service |
service_stop(name) |
Stop a Windows service |
net_isolate() |
Disconnect VM from network (host-VM channels stay up) |
net_connect() |
Reconnect VM to network (restarts adapter, renews DHCP) |
net_unplug() |
Full air-gap (link down via virsh) |
eventlogs(log?, since?, ids?, provider?, level?, max_events?) |
Query Windows event logs via Get-WinEvent (returns JSON array; CLI defaults to CSV) |
eventlogs_clear(log?, all_logs?, confirm) |
Clear event channels via wevtutil cl. confirm=True required (destructive). |
Defender:
| Tool | Description |
|---|---|
av_status(timeout?) |
Report Defender/AMSI protection state (Get-MpComputerStatus + Get-MpPreference) |
av_enable() |
Re-enable Defender real-time protection, AMSI, and behavior monitoring |
av_disable(confirm) |
Disable Defender completely — sets GP registry keys then reboots the VM. confirm=True required. |
HVCI / Virtualization Based Security:
| Tool | Description |
|---|---|
hvci_status(timeout?) |
Report HVCI/VBS state (DeviceGuard registry keys + bcdedit hypervisorlaunchtype) |
hvci_disable(confirm) |
Disable HVCI and VBS — sets registry keys + bcdedit then reboots the VM. confirm=True required. |
hvci_enable(confirm) |
Re-enable HVCI and VBS. Reboots the VM. confirm=True required. |
SMB shares and local users:
| Tool | Description |
|---|---|
share_create(name, path?, full_access?, change_access?, read_access?) |
Create an SMB share (creates backing folder if missing) |
share_delete(name, purge?, confirm?) |
Remove an SMB share; purge=True also deletes the backing folder |
share_list() |
List non-special SMB shares (name, path, description) |
share_grant(name, user, permission?) |
Grant Full/Change/Read access to a share |
share_revoke(name, user) |
Revoke an account's access to a share |
share_ls(name, path?) |
List files inside a share's backing folder |
share_mkdir(name, path) |
Create a directory inside a share |
share_write(name, path, content?, source?) |
Write a file inside a share (inline or upload from Kali) |
share_rm(name, path, confirm) |
Delete a file or directory inside a share. confirm=True required. |
user_create(username, password, full_name?, no_password_expire?) |
Create a local Windows user |
user_delete(username, confirm) |
Delete a local Windows user. confirm=True required. |
user_list() |
List local Windows users (name, enabled, last logon) |
Named pipes:
| Tool | Description |
|---|---|
pipe_list(filter?) |
Enumerate named pipes matching a pattern (JSON array) |
pipe_info(name) |
JSON: DACL/SDDL, mode, buffer sizes, max instances for a pipe |
pipe_connect(name, access?) |
One-shot pipe handle open; returns result or Win32 error |
pipe_open(name, access) |
Start a session — spawns a detached broker in the VM that holds the handle open |
pipe_send(session_id, data_hex) |
WriteFile through the session broker |
pipe_recv(session_id, size, timeout?) |
ReadFile through the session broker |
pipe_close(session_id) |
Close session + taskkill the broker |
Hypervisor-level kernel debug (via QEMU gdbstub, EDR-invisible):
On affected QEMU/KVM versions, debugger stop/resume corrupts Windows CET user
shadow-stack state. The debugger therefore fails closed unlessUserShadowStack is OFF. Preparation is explicit, saves the original policy,
and requires a reboot.
Stateless walks and symbol management — work against the live VM without an attached session:
| Tool | Description |
|---|---|
kdbg_doctor(port?) |
Fast non-disruptive readiness report: VM/agent, CET, cached symbol identity, reader/admission ownership, decomp capability, exact runtime/package provenance, and MCP catalog revision; labels live-base verification as not checked rather than guessing |
kdbg_cet_status() |
Report whether the current Windows boot is safe for QEMU GDB stop/resume |
kdbg_prepare(confirm) |
Back up the original mitigation policy and disable CET user shadow stacks; reboot required |
kdbg_restore_cet(confirm) |
Restore the backed-up mitigation policy; reboot required |
kdbg_start(port?, any_interface?) |
Start the gdbstub listener |
kdbg_stop() |
Stop the gdbstub listener |
kdbg_status(port?) |
Show stub state + reachability |
kdbg_symbols_load() |
Pull ntoskrnl.exe out, fetch PDB from msdl, persist symbols + struct layouts to ~/.winbox/symbols/ |
kdbg_user_symbols_load(pid, module, architecture?) |
Pull an x86/x64 module loaded in pid, fetch its matching PDB, and persist a separate architecture-correct symbol map |
kdbg_search(module, query, limit?, sha256?) |
Offline search over one exact symbol-store or persistent decomp-cache PE: ASCII/UTF-16 strings, exported names, validated MSVC x64 RTTI vtables, and direct RIP-relative string-xref leads. sha256 disambiguates same-named cached builds. Never opens the debugger socket or changes VM state. |
kdbg_sym(name, search?, limit?, rva?) |
Resolve mod!sym to VA or RVA; substring search supported |
kdbg_struct(type_name, field?, module?) |
Dump full struct layout or one field offset |
kdbg_ps() |
Walk PsActiveProcessHead (JSON: pid, dtb, eprocess, name) and return snapshot admission/timing metadata |
kdbg_vad(pid, address?, executable?, limit?, probe_header?, require_complete?) |
Exact-PDB, x64-only user VAD lookup or bounded map. Proves a range/protection/private-or-image fact, exposes explicit tree/output boundaries, and never treats a loader miss as a verdict. |
kdbg_vad_extract(pid, address, name, length?, require_complete?) |
In one bounded stop, prove the selected user VAD and preserve up to 8 MiB of its process-CR3 bytes as a mode-0600 immutable host artifact. Returns segment hashes/hole evidence and provenance, never raw bytes over MCP. |
kdbg_token(pid) |
Decode the target primary token through the exact _EPROCESS.Token fast reference: IDs, session, flags, raw privilege masks, and its proven object header. |
kdbg_handles(pid) |
Return the validated process handle-table root and build-specific entry-enumeration support. Public PDBs without the private entry union explicitly refuse slot decoding. |
kdbg_object(body) |
Decode an exact-PDB _OBJECT_HEADER only for a caller-proven canonical kernel object-body pointer. |
kdbg_capture(profile?, pid?, name?, require_complete?) |
One bounded RSP stop for an immutable process or system evidence artifact. A named artifact is atomically stored host-side; its snapshot phases/read accounting travel with it. |
kdbg_capture_diff(left, right, limit?, allow_identity_mismatch?) |
Purely offline bounded diff of matching capture identities; no RSP connection or target-memory read. |
kdbg_threads(pid, detail?, state?, wait_reason?, sort?, limit?, resolve?, include_current?, wait_objects?, wait_object_limit?, wait_owner_depth?, require_complete?) |
Bounded validated ETHREAD walk with validated head/link back-links, duplicate-TID rejection, structured partial evidence, optional strict completeness, scheduler summaries/filters, optional live module+local-symbol start attribution, exact KPCR→KPRCB current-vCPU identities, and optional exact-PDB wait-object / mutant-owner evidence. Every stop reports hard duration/read/byte budgets and actual read accounting; never claims arbitrary-thread registers, stacks, or speculative lock owners. |
kdbg_thread_triage(process_cap?, total_thread_cap?, sample_per_process?, result_limit?, resolve?, require_complete?) |
One bounded RSP snapshot ranking process-wide thread/runnable counts, newest and high-context-switch threads, and explicitly scoped suspicious starts. Every process-list, thread-budget, and per-process partial boundary is returned; strict callers can refuse any incomplete scope. |
kdbg_thread_baseline(pid, name?) |
Save one explicit complete host-side ETHREAD baseline, bound to VM boot, target PID/EPROCESS/CreateTime, and active nt symbol-store revision; includes snapshot admission/timing metadata |
kdbg_thread_diff(pid, name?, limit?) |
One explicit bounded comparison against a named baseline: created/exited threads, scheduler transitions, and wrap-aware context-switch deltas; refuses cross-boot/reuse/store comparisons and includes snapshot timing |
kdbg_triage(pid, thread_limit?, require_complete?) |
One bounded RSP snapshot: process identity, thread summary/top context-switch rows, current vCPUs, capped user modules, explicitly scoped unmapped-start leads, structured partial evidence/strict completeness, and stop-duration metadata |
kdbg_lm() |
Walk PsLoadedModuleList (JSON: base, size, name) |
kdbg_user_lm(pid) |
Walk native and WoW64 PEB loader views; every module is labelled x64 or x86 |
kdbg_read_va(pid, address, length) |
CR3-switching arbitrary-process read; works against PPL targets (1MB cap, hex bytes) |
kdbg_base_refresh() |
Re-resolve nt load base after ASLR reboot |
Session daemon — long-running debug session (attach once, drive across many tool calls):
Every kdbg_* MCP tool returns structured winbox.mcp/1 content:{schema, ok, result, error}. Failures use stable error codes, retryability,
and bounded recovery hints instead of prose that an agent must parse.
At a WoW64 compatibility-mode stop, the daemon uses 32-bit disassembly,
native-width stack entries, and a conservative hybrid call-chain walker.
Exact-build PDB FPO/frame records are preferred, followed by validated EBP
chains and bounded prologue simulation. Raw module-looking stack values remain
separate speculative candidates. Attach freezes native and x86 loader entries
into a bounded content-addressed manifest before the daemon takes QEMU's one
RSP connection. full remains the safe default; binaries skips network
enrichment, while cached-only performs no guest copy or download. A dry
preflight predicts bounded per-module work without mutation. PE machine, live
image size, hash, and PDB identity are verified before unwind metadata is
trusted; manual per-DLL preloading is no longer required.
At an active native WoW64 transition stop, kdbg_bt additionally derives the
CPU-area/context offsets from the exact wow64cpu.dll instruction stream and
PDB public symbols. A validated saved x86 context is stitched after the x64
transition frames, producing one explicitly marked windows-wow64-mixed
trace. An unrecognized build or invalid context remains a truthful native
partial trace with transition_error rather than guessed frames.
At an arbitrary x86 stop, QEMU does not expose the suspended native registers
directly. kdbg now recovers them without scanning: exact nt PDB layouts resolve
the firing CPU's self-validated KPCR, current KTHREAD, and persisted x64 user
trap frame; process identity, kernel-stack containment, native TEB identity and
stack bounds, x64 CS, exact wow64cpu image, and the first unwind step must all
agree. The already-returned syscall-stub frame is discarded, and the suspended
native callers are appended at boundary=wow64-x86-to-x64. Any failed
invariant preserves the ordinary x86 trace with transition_error.
| Tool | Description |
|---|---|
kdbg_attach(pid, port?, staging_policy?, preflight?, prewarm?, apply_intents?) |
Preflight or attach with full, binaries, or cached-only staging; optional Ghidra prewarming and explicit fresh-manifest application of saved breakpoint intents |
kdbg_detach() |
Tear down the session and leave the VM running |
kdbg_session() |
Show current daemon state (target pid, attach time, bp count, halted vs running) |
kdbg_target_status() |
Probe the captured EPROCESS/create-time identity as alive, exiting, gone, or unknown without rebinding PID reuse |
kdbg_bp_intent_add(target, mode?, condition?, wp_type?, wp_size?, actions?) |
Persist a detached module+0xoffset intent without resolving or touching the VM |
kdbg_bp_intents() |
List saved symbolic breakpoint intents without touching the VM |
kdbg_bp_intent_remove(intent_id) |
Remove one saved breakpoint intent by stable ID |
kdbg_bp(target, mode?, condition?, wp_type?, wp_size?, actions?) |
Install an explicit hardware/software breakpoint or hardware watchpoint. Targets also accept case-insensitive staged module+0xoffset; predicates support exact-width byte/word/dword/qword reads; actions additionally support bounded bytes/ascii/utf16 capture. Action hits append JSONL traces and auto-continue. |
kdbg_bps() |
List installed bps with hit/skip/error counters and canonical module+offset targets |
kdbg_bp_trace(bp_id, tail?, from_hit?, limit?, expression?, value?, errors_only?, summary?, top?) |
Bounded backward tail or cursor pagination over action traces, with projection/filtering and AI-sized value/error/distribution summaries |
kdbg_rm(bp_id) |
Remove an installed bp |
kdbg_cont(timeout?) |
Resume; block until next stop in target's CR3 set (KPTI-aware: kernel + user PML4) |
kdbg_cont_start(timeout?) |
Start a durable host-side continue and return a token immediately; survives MCP reloads |
kdbg_cont_poll(token?) |
Poll the current/tokenized continue job and retrieve its bounded terminal stop |
kdbg_cont_cancel(token?) |
Interrupt and cancel the durable continue job |
kdbg_step(over?, out?) |
Single-step, step over calls/syscalls, or step out via a temporary return-address breakpoint |
kdbg_interrupt() |
Halt a running cont via raw \x03 on the RSP socket |
kdbg_resume(port?) |
Recovery valve for a VM left paused after a debugger/client failure |
kdbg_regs() |
Dump GPRs + control regs from the firing vCPU |
kdbg_stack(n?) |
Hex-dump the top n native stack words (x64 qwords or WoW64 x86 dwords) |
kdbg_bt(depth?) |
Windows x64 .pdata, WoW64 x86 hybrid, or exact-build validated bidirectional mixed x64↔x86 transition backtrace, with explicit provenance and speculative candidates kept separate |
kdbg_context(disasm_count?, stack_qwords?, bt_depth?, memory?) |
Return one stop-epoch-pinned triage bundle with registers, symbolized assembly, stack, metadata-driven backtrace, breakpoints, and bounded optional memory reads |
kdbg_mem(va, length?, decode?) |
Read in target's CR3 (CR3-masquerade); bounded decode modes for hex, UTF-8, UTF-16LE, ASCII, C strings, and qwords |
kdbg_write_mem(va, hex) |
Write into target's CR3 (used for buffer-swap / agent-driven MITM workflows) |
kdbg_disasm(addr?, count?, instruction_bytes?) |
Symbol-annotated Capstone disassembly; raw bytes are opt-in |
kdbg_decomp(addr?, symbol?, module?, rva?, cursor?, before?, after?, full?, binary?, timeout?, analysis_timeout?, detail="compact", lines?, assembly="nearby", instruction_bytes?, runtime_vas?, callers?, callees?, allow_cold?) |
Resolve current RIP, runtime VA, symbol, or module+RVA, verify PE build identity, snapshot exact host content, and return stop-pinned RVA-linked assembly/pseudocode with bounded pagination. callers/callees add exact-PE direct-call evidence only; indirect flow is never invented. Cold Ghidra analysis is refused by default so a stopped target is never held while analysis runs; prepare offline first or explicitly opt in with allow_cold=true. |
kdbg_decomp_status() |
Report PyGhidra discovery, isolated worker/JVM state, durable project-cache status, and current decomp admission without starting the JVM |
kdbg_decomp_cache() |
List content-keyed binary/project sizes, analysis profiles, and LRU timestamps |
kdbg_decomp_cache_prune(max_bytes?, older_than_days?, sha256?, project?, module?, dry_run?) |
Dry-run-first exact/LRU pruning with reconciled accounting; applying requires the worker to be stopped |
kdbg_decomp_cache_repair(sha256) |
Delete one exact corrupt project cache and attempt one deterministic rebuild from its retained hash-addressed binary |
kdbg_decomp_prepare(module?, analysis_timeout?, background?, force_enrichment?) |
Analyze and exact-PDB-enrich cached modules without a debugger stop; background mode returns a durable token |
kdbg_decomp_prepare_status(token?) |
Read the latest or selected durable preparation result |
kdbg_decomp_cancel(request_id?, token?) |
Cooperatively cancel one active request or exact background preparation token; identities are mutually exclusive |
kdbg_ghidra_install(pull?) |
Build the checksum-pinned JDK 21 + Ghidra + PyGhidra Docker image |
kdbg_ghidra_run() |
Start and API-check the private, networkless persistent decompilation container |
kdbg_ghidra_stop() |
Stop/remove the labelled container while preserving analyzed projects and binary cache |
The pipe_open + pipe_send/recv/close family uses a persistent broker process per session (spawned as DETACHED_PROCESS | CREATE_NO_WINDOW inside the VM). IPC happens via cmd.json/result.json files on the VirtIO-FS share, so there's no VM round-trip on the polling path. This matters for protocols where a write on one handle must be answered on the same handle (stateless send/recv open fresh handles and never see each other's messages).
Breakpoint action traces
Use a staged relative target when symbols are absent, then attach one or more
actions to collect a bounded trace without stopping on every hit:
winbox kdbg bp mpengine+0xb52c40 --action rip --action rcx --action 'ascii(rcx,96)'
winbox kdbg bp-trace 0 --summary
Scalar actions use the predicate expression grammar (rax, rcx == 4,qword(rdx+0x10), poi(rcx)); capture actions are bytes(addr,n),ascii(addr,n), or utf16(addr,n). There are at most 16 actions, captures
are bounded to 256 bytes each/1024 bytes per hit/16 MiB per trace, and every
action hit is appended as JSONL then auto-continues. Use kdbg_bps to see the
canonical target and counters, and kdbg_bp_trace to page/filter the evidence.
Requires Python installed in the VM — this is now done automatically as part of winbox setup.
Architecture
Kali Linux
├── winbox control plane
│ ├── CLI (Python/Click)
│ └── MCP server (109 bounded agent tools)
├── hypervisor research plane
│ ├── QMP/HMP ────────────> VM + gdbstub lifecycle
│ ├── persistent RSP ─────> vCPUs, memory, break/watchpoints, stepping
│ ├── PDB/symbol store ───> Windows types, processes, modules, disassembly
│ └── Docker PyGhidra ────> private Unix API + exact RVA-focused pseudocode
├── guest interaction plane
│ ├── virtio-serial ──────> QEMU Guest Agent (execution + management)
│ ├── VirtIO-FS ──────────> ~/.winbox/shared/ <=> Z:\ in VM
│ ├── SSH ────────────────> OpenSSH Server (interactive PowerShell)
│ └── TCP listener ───────< ConPTY reverse shell (SYSTEM, resizable PTY)
├── containment/evidence plane
│ ├── libvirt nwfilter/link control
│ ├── bridge packet capture
│ └── DNS sinkhole + optional INETSim
│
└── Windows guest — Server Core 2022/2025 or Win11 (headless QEMU/KVM, plain VNC display)
├── QEMU Guest Agent ← primary exec channel
├── VirtioFsSvc (WinFsp) ← auto-mounts Z:\ on boot
├── OpenSSH Server ← interactive sessions
├── Python 3.13 ← required for MCP Python/ioctl/mem_read tools
├── x64dbg (C:\Tools\x64dbg) ← in-VM user-mode debugger
├── Defender disabled ← no AV interference
├── Firewall disabled ← no port blocking
└── NAT via libvirt ← reaches anything Kali can reach
The separation is deliberate: QMP owns lifecycle, one serialized RSP owner
controls debugger state, the guest agent handles in-guest automation, and
host-side networking enforces containment even when the guest is hostile.
Configuration
Override defaults in ~/.winbox/config (shell-style KEY=VALUE):
# VM resources
VM_NAME=winbox
VM_RAM=4096 # MB
VM_CPUS=4
VM_DISK=30 # GB
# Network
HOST_IP=192.168.122.1
# Credentials
VM_USER=Administrator
VM_PASSWORD=WinboxP@ss123
# Paths
WINBOX_DIR=~/.winbox
VIRTIO_ISO_URL=https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso
Filesystem Layout
~/.winbox/
├── config # user config overrides (optional)
├── decomp/ # private Docker/PyGhidra API state
│ ├── cache/binaries/ # immutable full-SHA-256 PE copies
│ ├── projects/ # durable version+SHA Ghidra projects
│ └── docker-build.log # image-build diagnostics
├── jobs.json # background job state (cleared on winbox destroy)
├── .setup.lock # fcntl lock — serializes concurrent winbox setup
├── id_ed25519 / .pub # SSH keypair (generated during setup)
├── disk.qcow2 # VM disk image
├── iso/
│ ├── SERVER_EVAL_x64FRE_en-us.iso # Windows Server 2022 eval ISO
│ ├── SERVER2025_EVAL_x64FRE_en-us.iso # Windows Server 2025 eval ISO (--os server2025)
│ ├── WIN11_ENT_EVAL_x64FRE_en-us.iso # Windows 11 Enterprise eval ISO (--os win11)
│ ├── virtio-win.iso # VirtIO drivers
│ ├── OpenSSH-Win64.zip # bundled OpenSSH
│ ├── winfsp.msi # WinFsp installer
│ ├── virtiofs.exe # VirtIO-FS service binary
│ ├── python-3.13.13-amd64.exe # Python 3.13 installer for the guest
│ ├── x64dbg.zip # x64dbg snapshot (extracted to C:\Tools\x64dbg)
│ └── unattend.img # built during setup
├── captures/ # winbox capture — host-side pcaps
│ ├── capture-<ts>.pcap
│ └── capture.pid # pidfile for the running capture
├── sinkhole/ # winbox sinkhole — DNS sinkhole state
│ ├── queries.log # captured C2 domains (tab-sep)
│ ├── sinkhole.pid
│ └── inetsim.conf # written by `sinkhole inetsim`
└── shared/ # VirtIO-FS share <=> Z:\ in VM
├── tools/ # your pentest tools
├── .msi/ # staging dir for winbox msi (cleaned up per-run)
└── loot/ # output directory
└── .jobs/ # background job log files
Testing
pytest # unit + coverage tests, no VM required
pytest -m integration # live end-to-end suite, drives the real VM
A bare pytest deselects everything marked integration, so it never touches a
VM you are using.
The live suite (tests/test_e2e_live.py) exercises every CLI command and every
MCP tool against whichever image ~/.winbox/config points at, and is written to
pass on all three profiles (server2022, server2025, win11) — where they
genuinely differ (Tamper Protection, Server Core's smaller service set, the
Python payload) it asserts the profile-appropriate behavior instead of skipping.
tests/e2e_manifest.py records how each command and tool is covered — live, or
excluded with a stated reason — and tests/test_e2e_coverage.py checks that
manifest against the real click tree and MCP registry. Adding a command or tool
fails the build until you say how it gets exercised, which is what keeps "we
test everything" a claim you can verify rather than one that quietly rots.
To validate a change across both images:
winbox setup --os server2022 -y && pytest -m integration
winbox setup --os server2025 -y && pytest -m integration
winbox setup --os win11 -y && pytest -m integration
License
MIT
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found