UnDefend: How a User-Mode File Lock Can Trip Up Windows Defender

A tiny C++ proof of concept targets the update gap, not the scanner, showing how timing, NTAPI calls, and shared file handles can undermine a security engine from standard-user context.

7 min read • View on GitHub • More from nightmare-eclipse

A wide black-ink illustration of a small hand slipping a wrench into a locked cabinet just as a larger hand reaches for the door. Inside, partially seated gears suggest an update mechanism that has been interrupted mid-cycle. The image explains the article's core idea: the attack is about timing and file access, not overpowering the security product.
UnDefend does not try to break Defender head on. It tries to be there first, then hold the door open.
Key Takeaways

Most security discussions focus on what gets blocked. UnDefend is interesting because it focuses on when. The repo's core move is simple: if a standard user can lock the right files at the right moment, even a heavyweight security engine can stumble while it is trying to update itself.

That makes the project less like a conventional AV killer and more like a timing lesson. Defender is strongest when its own maintenance path is smooth. UnDefend tries to make that path rough, and the result is a surprisingly ordinary failure mode: a file operation that cannot complete.

The weird part is how ordinary this attack is

There is no kernel exploit here. There is no admin prompt to bypass. The PoC leans on file semantics, handle ownership, and a narrow race window around Defender's update flow. That is what makes it unsettling. The weakness is not exotic. It is the kind of thing every operating system has to get right, every day.

A close-up black-ink schematic showing two diverging update paths. On one side, a staged definition update passes through a narrow corridor where a padlock blocks the door. On the other, a backup binary sits beside a service restart switch with a trapwire across the path. The image explains the repo's passive and aggressive modes as two ways of intercepting the same lifecycle.
Two modes, one premise: interrupt the update before the security engine finishes its transition.

Two modes, one premise

The heart of the repo is a race diagram. UnDefend is not trying to win a fight. It is trying to win first access.

Expected Defender behaviorWhat UnDefend targetsRequired privilegeFailure modeReliability
Download, stage, and replace files cleanlyThe same staging and replacement windowStandard user in the demonstrated pathUpdate error or engine disruptionOpportunistic, depends on timing
Keep definitions and platform files writable only during controlled maintenanceExclusive locks on files in transitNo admin rights shown in the PoCService cannot finish a write or swapHigher for passive mode, lower for aggressive mode
Recover quickly from failed updatesService restart and initialization transitionsNo kernel component neededDegraded availabilityFragile by design

The table hides the real drama, which is that both modes depend on the same idea: reach the relevant file before Defender does. Passive mode goes after signature updates. Aggressive mode watches for a platform transition and tries to seize the replacement path while the service is still mid-move.

Why NTAPI matters here

The implementation is intentionally close to the metal. Instead of leaning on higher-level file helpers, the code uses native Windows calls such as NtCreateFile and keeps track of handles in a protected list. That matters because the repo is not trying to be elegant. It is trying to stay close enough to the system that timing and locking behavior remain visible.

// High-level shape of the PoC
HANDLE h = NtCreateFile(..., OBJ_CASE_INSENSITIVE, ...);
LockFileEx(h, LOCKFILE_EXCLUSIVE_LOCK, ...);
TrackHandle(gHandleTracker, h);

// Passive mode watches signature locations and holds the lock
// Aggressive mode watches Defender state transitions and tries
// to lock backup or replacement binaries before initialization.

That handle tracker is the quiet center of the design. Once a file is locked, the program wants to keep it locked long enough to spoil the update. The critical section around the tracker is not there for style. It is there because the entire approach depends on persistent ownership of a small set of files.

The race condition is the real product

UnDefend is best understood as a state transition attack. Defender is safe while it is idle. It is also relatively safe while it has already finished replacing files. The gray zone in between is where the PoC lives. That gray zone is not glamorous, but it is exactly where a lot of real reliability bugs live too.

The interactive diagram above should be read as a race, not a flowchart. A token moves from source to staging to install. If UnDefend lands its lock before the install step completes, the package stops moving. In aggressive mode, the same idea applies to service restart and initialization instead of definition download.

What this is, and what it is not

What it isWhat it is not
A proof of concept for file-lock interference against a security productA polished, reliable weapon
A demonstration that low-privilege interference can matterA privilege escalation exploit
A timing and lifecycle lesson about Defender updatesA claim that Defender is universally bypassable
A rough repository with obvious experimental edgesA production-ready persistence framework

The project is explicit about its roughness. That is part of the signal. You can read it as a reminder that dangerous behavior does not always arrive wrapped in polished tooling. Sometimes it arrives as a crude demonstration that still works well enough to prove the point.

Why security teams should care

Security software is software. That sounds banal until a low-privilege process starts interfering with the software's own maintenance path. Then it becomes a product question, not just a malware question. Can the engine update itself cleanly under contention? Can it recover when a handle is already taken? Can it tolerate interference from the same user context it is supposed to protect?

Those are boring questions right up until they are not. UnDefend is interesting because it turns a boring operating-system primitive into a security lesson. The lesson is broader than Defender. Any security product that relies on staged replacements, temporary directories, and clean service restarts has a surface area worth testing.

Sources and repository notes