An open-source Process Monitor implementation for Windows: a kernel miniFilter driver captures process, file, registry and network activity in real time, a Rust SDK talks to the driver and parses the event stream, and a Rust/GPUI desktop GUI presents it.
This is a ground-up Rust rewrite of the SDK and GUI. The kernel driver is unchanged, and the original C++ implementation is kept under
cpp-backup/for reference. The Rust SDK is wire-compatible with the original Process Monitor driver and can read/write Procmon.PMLlogs.
An AI agent can drive capture and analysis through an MCP server or a skill — see MCP / Skill. The desktop GUI is powered by GPUI and GPUI-Component.
- Architecture
- Repository layout
- Features
- Screenshots
- Build
- Run
- SDK example
- PML logs
- MCP / Skill
- Kernel driver
- Known issues
- Status & roadmap
- License
- Acknowledgements
┌──────────────────────────────────────────────┐
│ GUI crates/gui (Rust + GPUI) │ event table · detail panel ·
│ │ filter/highlight · process tree
├──────────────────────────────────────────────┤
│ SDK crates/sdk (Rust) │ driver port · event parsing ·
│ │ process tracking · PML read/write
├──────────────────────────────────────────────┤
│ Kernel driver kernel/ (C, miniFilter) │ process/file/registry callbacks
└──────────────────────────────────────────────┘
The driver and the SDK communicate over a Filter Manager communication port; the
kernel/user-mode contract lives in kernel/logsdk.h, which the
Rust SDK mirrors with #[repr(C, packed)] structures.
openprocmon/
├── bin/ # Prebuilt binaries (e.g. the stock Process Monitor driver, PROCMON24.SYS)
├── cpp-backup/ # Original C++ SDK + WTL GUI, kept for reference
├── crates/ # Rust workspace
│ ├── sdk/ # procmon-sdk — driver comms, event parsing, PML read/write, symbols
│ ├── core/ # procmon-core — PML analysis layer (query / group-by / timeline)
│ ├── cli/ # procmon-cli — command-line + MCP server (the AI agent front-end)
│ ├── gui/ # procmon-gui — GPUI desktop app (live capture + .PML viewing)
│ └── example/ # procmon-example — console SDK demo (capture / save / replay)
├── docs/ # Design docs, logo, and screenshots
└── kernel/ # miniFilter driver (C, built with the WDK)
- Real-time monitoring of process, file system, registry, and network activity.
- Live filtering and highlighting by process name, PID, operation, path, result, or category.
- Process tree, and activity summaries for processes, files, registry, network, and cross-references.
- Call stack view with per-frame module resolution.
- Full
.PMLinteroperability with Sysinternals Process Monitor — files open both ways: capture with OpenProcMon and open the log in the real Process Monitor (event list, the per-process Properties dialog, and kernel-resolved call stacks all work), or open a Procmon-captured.PMLhere. - Full-control Rust SDK — drive everything programmatically: load/connect the driver, choose what to monitor, push filters, and consume the parsed event stream. The GUI is just one consumer (see SDK example).
- AI agent integration (MCP + skill) — capture and analyze from an AI agent over an MCP server (
procmon-cli mcp) or a drop-in skill; one query primitive (filter + group-by / numeric-metric aggregation) answers questions like "what did X write / connect to" without flooding the model (see MCP / Skill). - Modern, GPU-accelerated UI (GPUI) with a clean, contemporary design — light/dark themes and English/Chinese localization.
Process activity summary — per-process event counts with a category breakdown.
Settings — symbol/dbghelp paths, history limits, highlight color, theme and language.
- A recent Rust toolchain (stable) — see rustup.
- Windows (the SDK and GUI use Win32 APIs).
- For the kernel driver only: the Windows Driver Kit (WDK).
# Build everything (GUI, SDK, example)
cargo build
# Release build of the GUI
cargo build -p procmon-gui --release# GUI driving the real kernel driver (run elevated / as Administrator)
cargo run -p procmon-guiWhen procmon.sys sits next to the executable, the GUI loads and starts the
driver on demand; capturing the real system requires Administrator privileges.
Live capture and offline .PML reading flow through one EventSource, so the
consume loop is identical — only how you create the source differs.
Live capture — connect to the driver (loading the .sys on demand):
use procmon_sdk::{
Action, Column, DriverLoader, EventSource, FilterSet, MonitorFlags, Relation, Rule,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = EventSource::from_driver(
DriverLoader::new("OpenProcmon24", "procmon.sys"),
MonitorFlags::PROCESS | MonitorFlags::FILE | MonitorFlags::REGISTRY,
)?;
// An Include rule restricts the view to its matches: show only notepad.exe.
source.set_filter(FilterSet::new(vec![Rule::new(
Column::ProcessName,
Relation::Is,
"notepad.exe",
Action::Include,
)]));
// `events()` streams parsed events; fields are produced lazily.
for ev in source.events() {
if !source.is_visible(&ev) {
continue; // dropped by the active filter
}
println!(
"{:>6} {:<22} {:<16} {}",
ev.pid(),
ev.operation_name(),
ev.result(),
ev.path().unwrap_or_default(),
);
}
Ok(())
}Read a .PML — no driver needed; the loop is exactly the same:
use procmon_sdk::{Action, Column, EventSource, FilterSet, Relation, Rule};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = EventSource::from_pml("out.pml")?;
// Exclude rules hide their matches: drop temp-file noise.
source.set_filter(FilterSet::new(vec![Rule::new(
Column::Path,
Relation::EndsWith,
".tmp",
Action::Exclude,
)]));
for ev in source.events() {
if !source.is_visible(&ev) {
continue;
}
println!(
"{:>6} {:<22} {:<16} {}",
ev.pid(),
ev.operation_name(),
ev.result(),
ev.path().unwrap_or_default(),
);
}
Ok(())
}Run the bundled console demo:
# Live capture (run elevated). The optional .sys path loads the driver on demand.
cargo run -p procmon-example -- [C:\path\to\procmon.sys]OpenProcMon reads and writes the Sysinternals Process Monitor .PML format:
# Capture live, then save to a Procmon-compatible .PML
cargo run -p procmon-example -- --save out.pml [C:\path\to\procmon.sys]
# Replay a .PML (no driver needed)
cargo run -p procmon-example -- --pml out.pmlIn the GUI, use File ▸ Open to load a .PML.
procmon-cli is a command-line and MCP front-end that lets an AI agent drive
OpenProcMon is a capture-then-analyze tool: a capture writes a .PML, and every
analysis reads one. The single query primitive (filter + group-by) answers the
common questions ("what files did X write?", "registry persistence?", "network
endpoints?") without flooding the model with raw events.
cargo build -p procmon-cli --release
# Capture a program + its children for 10s (live capture needs Administrator):
procmon-cli capture --name app.exe --launch "app.exe" --duration 10
# Analyze any .PML (no elevation needed). The filter is an
# expression (&& / || / ! / in (...)); see `vocab` for the full syntax:
procmon-cli query --pml cap.pml --group-by Path \
--filter 'Category == "File System" && Operation == WriteFile'
procmon-cli vocab # exact column/operator/operation names + syntax
procmon-cli --help # all subcommandsTwo ways to wire it to an agent:
-
MCP server.
procmon-cli mcpserves the operations as MCP tools over stdio. 📖 See the full MCP guide (中文) for client setup (Claude Code / Claude Desktop / Codex / Cursor …) and a worked malware-.PMLanalysis. Quick start (Claude Code):claude mcp add --transport stdio --scope user openprocmon -- procmon-cli mcp
The server's
instructionsand thelist_filter_columnstool teach the agent the filter vocabulary and recipes, so no extra setup is needed. -
Skill (for CLI-driving agents). Copy
skills/procmon/into your own~/.claude/skills/— it teaches an agent theprocmon-clicommands and the filter cookbook.
Live capture requires Administrator (it loads the driver); analyzing a .PML
does not.
The miniFilter driver source is under kernel/; build it with the WDK.
The GUI and CLI load a driver image named PROCMON24.SYS: with the
embedded-driver feature (on by default) it is embedded from bin/PROCMON24.SYS at
build time and dropped to System32\Drivers on demand; with --no-default-features
they instead load a procmon.sys from next to the executable.
To use your own driver: build kernel/, sign it (or test-sign it), place the signed
.sys at bin/PROCMON24.SYS, then rebuild the GUI / CLI to embed it. A test-signed
driver requires test signing enabled / signature enforcement disabled on the machine
that loads it.
The SDK is wire-compatible with the original Process Monitor driver — it consumes the same event stream from either — and conversely this driver can stand in for the original to study how Process Monitor works, or as a starting point for your own EDR-style tooling.
- 32-bit (x86) is not supported. OpenProcMon targets 64-bit Windows only — the driver, the SDK's packed kernel structures, and the GUI all assume an x64 host. Running on 32-bit Windows is not supported and not currently planned.
- 32-bit
.PMLfiles are not supported. The PML reader/writer only handles the 64-bit PML format;.PMLlogs produced on a 32-bit host will not parse.
The Rust rewrite is under active development.
- Rust SDK: driver port, event parsing (process/file/registry/network)
- Process tracking, image metadata & icon extraction
- PML reader/writer (Procmon-compatible)
- GUI: event table, detail panel, filter/highlight, process tree, summaries
- Call stack with module resolution
- Save the current capture from the GUI
- AI MCP server and skills (
procmon-cli+procmon-cli mcp) - Performance optimization
- Boot logging capture
Released under the MIT License.
The desktop GUI is built on:
- GPUI — Zed's GPU-accelerated Rust UI framework.
- GPUI-Component — a UI component library for GPUI.



