A user-friendly, totally accessible, bullshit-free uninstaller for stubborn, misbehaving Windows applications. These are the apps that resist a normal uninstall by locking their files, denying permissions, scattering leftovers, or actively defending themselves. It ships today with built-in definitions for four notoriously stubborn security suites (McAfee, Norton, Avast, and AVG), plus the companion browser, VPN, cleanup, and tune-up add-ons that linger after them. The removal engine is general, though: every app goes through the same escalation, and the catalog of supported products is meant to grow.
Author: PratikP1
- Removes McAfee Total Protection, Norton 360 / Norton Security, Avast Antivirus / Avast Premium Security, and AVG AntiVirus / AVG Internet Security completely: files, directories, registry keys, Windows services, and scheduled tasks.
- Sweeps same-vendor companion products during cleanup, including McAfee LiveSafe / WebAdvisor, Norton Secure VPN / Utilities, Avast Secure Browser / Cleanup, and AVG Secure Browser / TuneUp leftovers.
- Fully accessible on Windows - built on native task dialogs, the same modern dialog Windows itself uses. Every product is its own labelled button rather than a "Yes"/"No" whose meaning lives in the body text, so NVDA, JAWS, and Narrator announce exactly what each control does. Keyboard-only throughout: Tab/Shift+Tab between controls, arrow keys between product buttons, Enter/Space to activate, Alt+letter access keys, Esc to cancel, and F1 for the bundled help guide. Dialogs scale correctly on high-DPI displays. The CLI remains available as a fallback for development and test environments.
- Shows exactly what it will delete before it deletes anything: expand Show what will be removed on the confirmation screen for the full list of folders, driver files, services, scheduled tasks, and registry keys.
- Reports live progress. The removal runs on a worker thread behind a progress bar that names each stage, instead of freezing the window - which, with a screen reader, is indistinguishable from a crash.
- Explicitly targets 64-bit Windows 10 and Windows 11.
- Requests Administrator on launch via an embedded application manifest, so the Start-menu shortcut triggers a UAC prompt instead of silently failing every removal action.
- Deletes self-healing scheduled tasks before services and file paths so a stubborn app cannot immediately reinstall itself during cleanup.
- Will not brick your boot. A kernel driver's
.sysfile is only deleted once its service has been removed. If the service cannot be removed, the driver file is left alone and reported as skipped, because deleting the image of a still-registered boot-start driver can stop Windows from starting. - Handles apps that fight back, without Safe Mode. Some applications resist
removal. They lock their files, deny permissions, or load a kernel driver that
blocks deletion while Windows runs (Avast and AVG are the standout case). Safe
Mode would get around that, but Windows 10 often loads no audio driver there,
so a screen reader cannot start. Instead, Wixen runs the app's own silent
uninstaller, elevates to
NT AUTHORITY\SYSTEMwhere Administrator is not enough, takes ownership of permission-locked leftovers, and queues anything still locked for deletion during the next normal restart, then finishes the job automatically after you reboot. - Follows your actual Windows layout. Locations are resolved from
%ProgramFiles%,%ProgramData%, and%SystemRoot%rather than assumingC:\, and every target is validated before deletion: drive roots, Windows, System32, Program Files, ProgramData, and Users can never be targeted. - Packaged as a standalone Windows installer via Inno Setup.
- Ships with an installed HTML help guide for release builds.
- Written in pure Rust; no runtime or build dependencies.
- Wixen itself is cleanly uninstallable through the standard Windows Add or Remove Programs flow.
- Tested with red/green TDD, and checked with mutation testing
(
cargo-mutants) and fuzzing (cargo-fuzz), both enforced in CI, so a behaviour that no test pins down fails the build.
| # | Product | Notes |
|---|---|---|
| 1 | McAfee Total Protection | Also removes common McAfee LiveSafe and WebAdvisor / SiteAdvisor leftovers |
| 2 | Norton 360 / Norton Security | Also removes common Norton Secure VPN and Norton Utilities leftovers |
| 3 | Avast Antivirus / Avast Premium Security | Also removes common Avast Secure Browser and Avast Cleanup leftovers; self-protection is handled automatically, no Safe Mode needed |
| 4 | AVG AntiVirus / AVG Internet Security | Also removes common AVG Secure Browser and AVG TuneUp leftovers; self-protection is handled automatically, no Safe Mode needed |
Want another product removed? File an issue.
- Windows 10, 64-bit
- Windows 11, 64-bit
- The packaged installer is currently
x86_64-pc-windows-msvc; 32-bit Windows is not supported.
- Download the latest
WixenUninstaller-Setup-*.exefrom the Releases page. - Right-click the installer and choose Run as administrator.
- Follow the wizard. After installation, launch Wixen Uninstaller from the Start menu.
- Choose the product to remove. Each one is its own button, labelled with the product name and the companion leftovers it also sweeps up. Move between them with the arrow keys or Tab, and activate with Enter or Space.
- Review the plan. Expand Show what will be removed to read the exact folders, driver files, services, scheduled tasks, and registry keys before anything is deleted. Focus starts on Cancel, so pressing Enter by reflex never begins a removal - choose Remove it (or Alt+R) deliberately.
- Watch the progress bar. A removal cannot be interrupted part-way, because stopping half-finished can leave the product broken.
- Review the completion report. It separates real errors from actions skipped for safety; expand Show details for the full list.
- For self-protecting products (Avast, AVG), Wixen runs the product's own uninstaller and, if any file is still locked, queues it for removal during the next restart, with no need for Safe Mode. If files were queued, Wixen registers itself to finish automatically after you restart.
- Restart Windows to finish the cleanup. Removing kernel drivers and services only fully takes effect after a reboot, and any queued files are deleted then.
Running it again is safe. Wixen re-checks every target on each run, and
anything already gone is reported as already removed rather than an error. So if
an earlier run, or an older version of Wixen, left part of a product behind,
just run it again. It re-attempts the whole removal with its full escalation:
running the product's own uninstaller, taking ownership of permission-locked
files, boot-time deletion, and running as NT AUTHORITY\SYSTEM. That clears most
of what was left. Finishing may take a restart, since anything still locked
is queued for boot-time deletion and Wixen resumes on its own after a normal
reboot.
Note: The tool must be run with Administrator privileges. Both the installer and the installed application request elevation, so Windows prompts you automatically.
SmartScreen: Releases are not code-signed, so Windows will warn you the first time you run the installer. Verify your download against the
.sha256file published alongside it, then choose More info > Run anyway:Get-FileHash -Algorithm SHA256 .\WixenUninstaller-Setup-0.5.0.exeHelp file: The installer places
WixenUninstallerHelp.htmlnext to the application executable and opens it when you press F1 from the Windows UI.Wixen uninstall: To remove Wixen itself, use Settings > Apps > Installed apps (or Add or Remove Programs) and uninstall Wixen Uninstaller like any other Windows application.
- Rust toolchain 1.88 or newer (2024 edition; 1.88 is where let-chains stabilised)
- Inno Setup 6 (for building the installer; Windows 10/11 64-bit only)
# Debug build (for development)
cargo build
# Release build (for the installer)
cargo build --release --target x86_64-pc-windows-msvccargo test --features test-utilsThe test-utils feature is required: it exposes StubExecutor, and without it
the integration test target is skipped rather than run.
The suite is in three layers:
| Target | Covers |
|---|---|
unit tests in src/ |
pure logic: plans, path resolution, screen wording, the dialog builder and its Win32 struct layout |
tests/integration.rs |
the executor pipeline end to end against a stub: boot-safety guards, error accumulation, progress ordering |
tests/cli.rs |
the real compiled binary, driven over a pipe, the only way to reach main and the stdio dispatch in ui |
Clippy must be run against the Windows target too, because the Win32 modules are compiled out on Linux, so host-only linting cannot see them.
cargo fmt --all --check
cargo clippy --all-targets --features test-utils -- -D warnings
rustup target add x86_64-pc-windows-msvc
cargo clippy --all-targets --features test-utils \
--target x86_64-pc-windows-msvc -- -D warningsEvery behaviour is expected to be pinned by a test that fails without it, and mutation testing is how that is checked rather than assumed. CI runs the same script and fails the build if anything new survives.
cargo install cargo-mutants
./scripts/check-mutants.shA surviving mutant means the code could be changed that way and the suite would still pass, so that behaviour is not really covered. The fix is to write the test that fails without it.
.cargo/mutants-baseline.txt lists the handful of survivors that are tolerated.
Every entry must be an equivalent mutant, where the mutated program is
genuinely identical and no test could tell the difference, and each carries a
comment saying why. Adding to that file is a deliberate, reviewable act; the
default answer to a survivor is a new test.
Configuration lives in .cargo/mutants.toml. That exact path is the only one
cargo-mutants reads. It enables the test-utils feature and skips the
code that calls into the Win32 API, which is compiled out on Linux and could
never be covered there.
rustup install nightly
cargo install cargo-fuzz
cd fuzz
cargo +nightly fuzz run fuzz_parse_input -- -max_total_time=60
cargo +nightly fuzz run fuzz_from_slug -- -max_total_time=60
cargo +nightly fuzz run fuzz_from_menu_index -- -max_total_time=60
cargo +nightly fuzz run fuzz_resolve_path -- -max_total_time=60fuzz_resolve_path is the important one: it hammers the parser that decides
what Wixen is willing to delete recursively.
- Compile the release binary (see above).
- Open
wixen_uninstall.issin the Inno Setup Compiler. The script auto-detects eithertarget\x86_64-pc-windows-msvc\releaseortarget\release, and CI can overrideAppVersion,BinaryDir, andOutputDirwithISCC /D...arguments. - Click Build > Compile (or press
F9). - The installer is written to
installer_output/.
.github/workflows/ci.yml runs on every pull request and on pushes to main:
cargo fmt --all --check- Clippy on the host target and on
x86_64-pc-windows-msvc, both with-D warnings cargo test --locked --features test-utilson Linux and Windows- A short smoke run of every fuzz target
- Mutation testing, failing if any behaviour is left unpinned by a test
- A Windows release build that asserts the elevation manifest is embedded,
compiles
wixen_uninstall.iss, and uploads the installer as an artifact
.github/workflows/release.yml is driven by tags:
# 1. Bump the version in Cargo.toml and add a CHANGELOG entry.
# 2. Tag it. The workflow refuses to publish if the tag and Cargo.toml
# version disagree.
git tag v0.5.0
git push origin v0.5.0The workflow re-runs the full check suite, builds the installer, generates a
SHA-256 checksum, and publishes a GitHub Release using docs/release-notes.md
as the body.
src/
lib.rs - module declarations
product.rs - Product enum + parsing helpers
paths.rs - Windows location resolution + delete-target validation
plan.rs - RemovalPlan (pure data; no I/O)
executor.rs - Executor trait, the guarded sweep, and the escalating
execute_full / finish_resume orchestration
uninstall.rs - parse a registry uninstall string into program + args (pure)
vendor.rs - run the product's own silent uninstaller (I/O boundary)
stats_ini.rs - enable Avast/AVG fully-silent uninstall via stats.ini (pure)
escalation.rs - per-artifact next step: take ownership, defer, skip, or fail
forceful.rs - take-ownership / delayed-delete boundary + the per-file loop
reboot.rs - persist a suspended run and register the RunOnce resume
resume.rs - ResumeState: what a run must finish after a restart (pure)
system_exec.rs- re-launch as SYSTEM (schtasks) to run the removal headless,
and read its report back across the process boundary
elevation.rs - Administrator privilege detection
menu.rs - accessible CLI fallback menu
ui.rs - screen wording (pure, unit tested) + platform dispatch
ui/
task_dialog.rs - safe wrapper over Win32 TaskDialogIndirect
windows.rs - the Windows screens, assembled from ui.rs wording
main.rs - entry point; the --execute (SYSTEM) and --resume branches
docs/
automated-removal.md - design + plan for the escalation and resume flow
WixenUninstallerHelp.html - installed HTML help guide
release-notes.md - body of the published GitHub Release
scripts/
check-mutants.sh - mutation run + baseline comparison, used by CI
tests/
integration.rs - executor pipeline tests against a stub
cli.rs - drives the compiled binary over a pipe
fuzz/
fuzz_targets/
fuzz_parse_input.rs
fuzz_from_slug.rs
fuzz_from_menu_index.rs
fuzz_resolve_path.rs
fuzz_parse_uninstall.rs
build.rs - embeds the Windows elevation manifest
wixen_uninstall.manifest - requireAdministrator, longPathAware, DPI awareness
wixen_uninstall.iss - Inno Setup packaging script
ui.rs decides what every screen says; ui/windows.rs decides how it is
drawn. That split is deliberate: the wording, the details pane, the report
summary, and the truncation rules are plain functions over plain data, so they
are unit tested on Linux, while only the TaskDialogIndirect calls are
Windows-only.
The dialogs need version 6 of the common controls, which
wixen_uninstall.manifest declares. That dependency is load-bearing, not
cosmetic: TaskDialogIndirect does not exist in the version 5 comctl32 that
lives in System32, so a missing dependency stops the process from starting at
all. CI asserts the manifest is embedded and then launches the built binary to
prove it resolves at run time.
executor::execute always runs in this order, and the order is load-bearing:
- Scheduled tasks, so a self-repair task cannot reinstate what comes next.
- Services, releasing file handles and, critically, deregistering drivers before their images are touched.
- Files, with guarded driver images skipped if step 2 failed for them.
- Registry keys, which is what finally makes the product invisible to Windows.
executor::execute_full wraps that sweep in an escalation ladder so removal
never needs Safe Mode. In Safe Mode, Windows 10 often has no audio and a screen
reader cannot start. The whole run prefers to execute as NT AUTHORITY\SYSTEM
(via a transient scheduled task), reaching artifacts an Administrator cannot
touch; if that relaunch cannot be arranged it falls back to running in-process
under Administrator. First it runs the app's own silent uninstaller (read
from the registry, never guessed), which can undo whatever the app did to
defend itself.
Then the guarded sweep above runs. Each file the sweep cannot delete is
escalated one rung at a time by forceful::resolve_file, whose every branch is
chosen by the pure escalation::next_step:
- an access-denied file → take ownership, reset its ACL, retry;
- a still-locked file → queue it for deletion during the next boot
(
MoveFileExwithMOVEFILE_DELAY_UNTIL_REBOOT); - a guarded driver whose service survived → skipped at every rung, so the boot-safety invariant holds on the delayed path exactly as on the immediate one.
When anything is queued for boot-time deletion the run is suspended, not
finished: reboot::arrange_resume writes a small state file and a RunOnce
entry, so after a normal restart Wixen relaunches with --resume, deletes
the now-unlocked files' registry keys, reports, and clears up. Every decision in
this ladder is pure and tested on Linux against stubs; only the Win32 calls it
drives are Windows-gated.
See SECURITY.md for how to report a vulnerability and for the constraints Wixen places on its own privileges.
See CHANGELOG.md.
MIT