-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Line 209 of `UnDefend.cpp`, inside `WDKillerCallback`, reads: ```c // if you are reading this, you are autistic. ``` The researcher who wrote BlueHammer, who wrote RedSun, who left Windows Defender unpatched for three weeks before Microsoft touched it, they knew people would read this code. They left a comment for the audience they expected. This is the third zero-day from Nightmare-Eclipse in April 2026. BlueHammer patched Tuesday. RedSun still open. UnDefend dropped this week, no CVE yet, no patch on the horizon. Each one is a different weapon against the same target. Unlike the first two, UnDefend requires no privilege escalation. It runs as a standard user. It doesn't need SYSTEM. It doesn't use oplocks or object namespace symlinks or Cloud Files APIs. What it does is simpler and in some ways more dangerous: it makes Defender permanently unable to update its signatures, from an account with no special access, using file locking primitives that have existed since Windows NT. The README adds one more detail that isn't in the code: > *"Now funnily enough, I found a way to lie to the EDR web console to show that defender is up and running with the latest update even if it's not. I was thinking about publishing the code but after thinking about it, it will cause waaay too much damage so I think I'll keep that stuff stashed for now."* Same author. Same month. Same decision: publish the proof, withhold the weapon. In BlueHammer it was two comment characters separating the PoC from a full domain credential harvest. In UnDefend it's unshipped code separating a noisy DoS from a silent, invisible persistence enabler. Let's walk the code. ## What the Tool Actually Does `UnDefend.cpp` is 452 lines. It has four independent mechanisms that collectively lock Defender out of its own update pipeline. No mechanism depends on another, if one fails, the others still run. Standard user throughout. The entry point (`wmain`) does three things before entering its main loop: 1. Reads `HKLM\SOFTWARE\Microsoft\Windows Defender\ProductAppDataPath` to find Defender's data directory 2. Constructs the `Definition Updates` subdirectory path 3. Immediately calls `TryLockBackup()` That third step is why rollback doesn't save you. ## Mechanism One: Kill the Rollback Before the Fight Starts `TryLockBackup()` runs before any threads are spawned. It opens two files: ```c wcscat(gbackupfile1, L"\\Backup\\mpavbase.lkg"); wcscat(gbackupfile2, L"\\Backup\\mpavbase.vdm"); ``` `mpavbase.vdm` is the active virus definition module. `mpavbase.lkg` is the last-known-good backup, the copy Defender falls back to when an update fails or corrupts the active signatures. The open call is `NtCreateFile` with no sharing flags at all, the fourth sharing parameter is `NULL`: ```c ntstat = NtCreateFile(&hlock1, GENERIC_READ | SYNCHRONIZE | GENERIC_EXECUTE, &objattr, &iostat, NULL, FILE_ATTRIBUTE_NORMAL, NULL, // <-- no sharing FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT, NULL, NULL); ``` `FILE_SYNCHRONOUS_IO_ALERT` means the kernel holds the thread's I/O context synchronously, this is an internal NT flag that Defender's own file operations use. The open succeeds because nothing has locked these files yet. Once it succeeds, `LockFileEx` places a blocking exclusive byte-range lock across the full file: ```c LockFileEx(hlock1, LOCKFILE_EXCLUSIVE_LOCK, NULL, li.LowPart, li.HighPart, &ov); ``` Now: if a signature update fails and Defender tries to reload from backup, it calls `NtCreateFile` on `mpavbase.lkg` and gets `STATUS_SHARING_VIOLATION`. The fallback is gone. Defender is stuck on whatever signatures it had when `TryLockBackup()` ran. ## Mechanism Two: The Staging Directory Race The main loop in `wmain` watches `Definition Updates\`, the directory where Windows Update stages new signature packages before Defender loads them. It uses `ReadDirectoryChangesW`: ```c ReadDirectoryChangesW(hmonitordir, notifydata, sizeof(notifydata), TRUE, FILE_NOTIFY_CHANGE_SIZE, &retbytes, NULL, NULL); ``` `FILE_NOTIFY_CHANGE_SIZE` specifically. Not `FILE_NOTIFY_CHANGE_LAST_WRITE`. The notification fires on file size changes, which means the write must already be in progress or complete before the callback triggers. This is intentional: the attacker doesn't want to race against an empty file, they want to grab a file with content that Defender is about to load. When a notification arrives with `FILE_ACTION_MODIFIED`, the main loop spawns `UpdateBlockerThread` for that file. The thread opens the file: ```c stat = NtCreateFile(&hlock, GENERIC_READ | SYNCHRONIZE, &objattr, &iostat, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE | FILE_SHARE_DELETE, // <-- no FILE_SHARE_READ FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, NULL); ``` The sharing flags are the mechanism. `FILE_SHARE_WRITE | FILE_SHARE_DELETE` is explicitly present, which means Windows Update's write process can keep writing. `FILE_SHARE_READ` is explicitly absent, which means any process that tries to open this file for reading gets `STATUS_SHARING_VIOLATION`. Defender's signature loader (`MsMpEng.exe`) opens `mpavbase.vdm` for reading. UnDefend holds it open while denying read-sharing. The loader fails. The update fails. The `FILE_SHARE_WRITE` flag is why the attacker doesn't fight Windows Update at all, it lets the write finish, then blocks the read. After the open, `LockFile` places a second layer, a non-blocking exclusive byte-range lock on the full file: ```c if (!LockFile(hlock, offset.LowPart, offset.HighPart, li.LowPart, li.HighPart)) { ... } ``` `LockFile` (not `LockFileEx`) returns immediately, if it fails, the thread moves on. This is belt-and-suspenders: the sharing violation is the primary block, the byte-range lock is the fallback if something manages to open a compatible handle. There's a large block of commented-out code in `UpdateBlockerThread` (lines 101-122) that attempted to filter files by CLSID-formatted subdirectory names, only lock files in legitimate update packages, not everything. The author disabled it: ```c if (1/*(!CLSIDFromString(mx, &tmp)) || _wcsicmp(__cmp, L"Backup") == 0*/) ``` The condition is always true. Lock everything that moves in the directory. Crude, but it means zero false negatives. ## Mechanism Three: The Engine Restart Hook `WDKillerThread` registers an asynchronous service status notification for when `WinDefend` stops: ```c NotifyServiceStatusChangeW(hsvc, SERVICE_NOTIFY_STOPPED, &svcnotify); SleepEx(INFINITE, TRUE); ``` `SleepEx` with `TRUE` puts the thread in an alertable wait, Windows will interrupt it via APC when the service notification fires. When WinDefend stops (as it does during platform updates, when `MsMpEng.exe` itself is being replaced), `WDKillerCallback` executes: ```c DWORD retcode = RegQueryValueEx(wdkey, L"SignatureLocation", NULL, NULL, (LPBYTE)sigpath, &retsz); // ... wcscat(sigpath, L"\\mpavbase.vdm"); ``` The callback reads `HKLM\SOFTWARE\Microsoft\Windows Defender\Signature Updates\SignatureLocation` to find where the live signatures are (distinct from the staging directory), then opens and locks `mpavbase.vdm` at that path. No sharing, exclusive lock, `FILE_SYNCHRONOUS_IO_ALERT` again: ```c ntstat = NtCreateFile(&hlock, GENERIC_READ | SYNCHRONIZE | GENERIC_EXECUTE, &objattr, &iostat, NULL, FILE_ATTRIBUTE_NORMAL, NULL, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT, NULL, NULL); LockFileEx(hlock, LOCKFILE_EXCLUSIVE_LOCK, NULL, li.LowPart, li.HighPart, &ov); ``` When the new `MsMpEng.exe` starts after the platform update completes, it tries to load signatures. The live `mpavbase.vdm` is locked. Defender comes up running, service status shows RUNNING, but it can't load its signature database. It's running blind. This is the aggressive mode path. The README notes it only triggers during major platform updates (when the engine binary itself is replaced), which don't happen on the same cadence as definition updates. The passive path (mechanism two) runs continuously regardless. The commented-out line at the end of `wmain` makes the relationship explicit: ```c // run in killer mode // WaitForSingleObject(wdkiller,INFINITE); ``` Uncommenting that would block the main thread on the killer thread, disabling the passive path. The author chose to run both simultaneously. ## Mechanism Four: MRT `MRTWorkerThread` runs the same `ReadDirectoryChangesW` + `UpdateBlockerThread` pattern against a hardcoded path: ```c wchar_t _wdupdatedir[] = { L"\\??\\C:\\Windows\\System32\\MRT" }; ``` The Malicious Software Removal Tool maintains its own detection database, separate from Defender's signature files. UnDefend locks that too. Every component of Microsoft's on-device malware detection, Defender signatures, Defender engine, MRT, has a corresponding lock. ## Why It Stays Running Every lock in UnDefend is a byte-range lock held by an open file handle. Byte-range locks are advisory and process-scoped: they release automatically when the handle closes, which happens when the process exits. `AddHandle()` exists to keep every handle alive in the process: ```c void AddHandle(HANDLE hlock) { // shit code but works i guess static unsigned int handlecount = 0; HANDLE* ntracker = (HANDLE*)malloc((++handlecount + 1) * sizeof(HANDLE)); // ... } ``` The author's self-assessment is accurate, it's a manually-grown heap array, realloc'd on every call, protected by a CRITICAL_SECTION. But the goal is just to prevent the handles from going out of scope. As long as `UnDefend.exe` runs, the locks hold. If the process is killed, all locks release within milliseconds and Defender can update normally. This is the detection surface. A process with a large number of open handles to files under `%ProgramData%\Microsoft\Windows Defender\Definition Updates\` is the indicator. Specifically: handles to `.vdm` and `.lkg` files in that tree, held by a non-Defender process. ## What Chaotic Eclipse Held Back The code that shipped blocks updates and makes them fail visibly. Windows displays an error: Defender can't update, last update failed. An EDR operator watching their dashboard sees red. They know something is wrong. The README describes code that wasn't shipped: > *"I found a way to lie to the EDR web console to show that defender is up and running with the latest update even if it's not."* Defender reports its health status, signature version, last update time, engine version, overall protection status, through the `MSFT_MpComputerStatus` WMI class. This is the provider that Microsoft Endpoint Manager, SCCM, Intune, and every third-party SIEM integration queries to determine whether a given machine has current protection. If you can write to that provider, or intercept its output, you can report a signature date and version that doesn't match the locked files on disk. Without the console spoofing code, UnDefend is a DoS with a visible signature: update errors accumulate, the security dashboard shows protection degraded. Noisy. With it, the dashboard shows current signatures. The security team sees green. The machine is actually running signatures from whenever UnDefend started, weeks ago, a month ago, however long it's been running. Any new malware developed after that date is invisible to Defender. The attacker gets an indefinite detection window, and the defenders have no signal that anything is wrong. The difference between the two is the same difference Chaotic Eclipse navigated in BlueHammer: the line between "this demonstrates the vulnerability" and "this is a weapon for sustained compromise." In BlueHammer, SYSTEM and SECURITY hives were commented out of `filestoleak[]`. Here, the WMI spoofing code was written and withheld. The researcher drew the line in the same place twice. It's worth noting that both times, the withheld component is the one that makes the attack silent. ## The Trilogy Three tools. One month. One researcher. They compose into a complete attack chain, and nobody in the public coverage has connected the sequence with the code. **RedSun** uses Defender's SYSTEM write primitive against itself. The attack plants a batch oplock on a file in the update staging path, registers a fake Cloud Files sync provider named `"SERIOUSLYMSFT"` to stall Defender's VSS access, then stamps a mount point reparse on the update directory pointing to `\??\C:\Windows\System32`. When the oplock breaks and Defender resumes, it follows the redirected path and writes `TieringEngineService.exe` into System32 with `NtCreateFile` using `FILE_SUPERSEDE`, create-or-replace, at SYSTEM privilege. The Storage Tiering Engine Service is a legitimate Windows service. The next time it starts, it runs attacker-supplied code as SYSTEM. **BlueHammer** (CVE-2026-33825) uses the same oplock plus Cloud Files plus object manager architecture, but changes the fake sync provider from `"SERIOUSLYMSFT"` to `"IHATEMICROSOFT"` and redirects the write at `\Windows\System32\Config\SAM` instead of a system binary. The result isn't code execution, it's the credential database, readable by the attacker after Defender writes it to their staging path. **UnDefend** doesn't use any of that. Standard user. No race condition, no object namespace manipulation, no Cloud Files freeze. It holds byte-range locks on the files Defender needs to load signatures. Permanent update block, no elevation required. The three form a sequenced operation: UnDefend creates a detection window by preventing new signatures from loading. Once the window is established, BlueHammer (or any other LPE) runs against a Defender that cannot see whatever payloads have been released since the lock started. RedSun provides the SYSTEM code execution that closes the loop. No tool in the chain communicates with any other. Each is independently deployable. ## The Security Model These Three Tools Break Windows Defender requires SYSTEM privilege to remediate files because it needs to modify locked or protected binaries that user-space processes cannot touch. That design decision is correct, the kernel enforces it and it cannot be bypassed. RedSun and BlueHammer do not bypass it. They weaponize it. The trust model's assumption is: "Defender is elevated, therefore its writes are legitimate." The actual mechanism is: "Defender writes to whatever path resolves at write time." These two statements are only equivalent if path resolution is controlled by the OS and not the user. A standard user can influence path resolution before the write happens. `FSCTL_SET_REPARSE_POINT` requires no elevation for a directory the user owns. `CfRegisterSyncRoot` requires no elevation. `NtCreateSymbolicLinkObject` in a session-local namespace requires no elevation. None of these are bugs. They're designed behaviors. The attack chains them in a sequence Defender's designers did not consider. UnDefend and the withheld spoofing code break a different assumption. Defender's health reporting is authoritative because it runs as a SYSTEM service queried through a trusted channel, `MSFT_MpComputerStatus`, the WMI class that Endpoint Manager, SCCM, and Intune read to assess machine protection state. The management console trusts that class because the service that populates it is trusted. The withheld code demonstrates that trust is not structurally enforced. It can be spoofed. The mechanism is unshipped, but the researcher confirmed it works. Both assumptions, that elevated writes are legitimate, and that the health report is authoritative, are reasonable. Neither is verifiable at runtime without changes to how Windows handles path resolution and WMI provider trust. A patch for BlueHammer doesn't fix the class of vulnerability. RedSun remains unpatched. UnDefend has no CVE. The author changed the sync provider name from `"SERIOUSLYMSFT"` to `"IHATEMICROSOFT"` between the first and second drops. The code got more sophisticated. The message got clearer. The third tool dropped with no CVE assigned and no patch in sight. The comment at line 209 was directed at whoever opened the source file. You opened it. The code works. ## What You Can Do on Monday **Detection.** Hunt for non-Defender processes holding file handles under `%ProgramData%\Microsoft\Windows Defender\Definition Updates\`. The specific tells: handles to `*.vdm` and `*.lkg` files in that tree, exclusive byte-range locks, open handles to files in `C:\Windows\System32\MRT\`. Sysinternals Handle (`handle.exe -a mpavbase`) surfaces this immediately. **Monitoring.** Don't trust the Defender health dashboard alone. Cross-reference reported signature dates against actual `.vdm` file timestamps on disk. If the WMI-reported signature date is newer than the file's last-modified timestamp, something is wrong. (The withheld spoofing code would break this check. It isn't shipped yet.) **Process monitoring.** `UpdateBlockerThread` spawns a new thread per directory notification. A process that has been running against an active machine will have accumulated dozens of threads, each holding a file handle. The thread count and handle count profile is distinctive. **Defender update failures.** If `MsMpEng.exe` is failing to apply updates (`EVENT_ID 2001` in the Windows Defender operational log) with no system or policy explanation, check for non-Defender handle holders on the signature files. **RedSun and UnDefend.** For RedSun: look for `CfRegisterSyncRoot` calls from processes other than known sync clients, mount point reparse points on Cloud Files sync roots, and unexpected writes to `%WINDIR%\System32\TieringEngineService.exe`. For UnDefend: the process must persist. Terminate it and Defender recovers. Find it before it daemonizes. *PGP signature: [undefend.md.asc](/sigs/undefend.md.asc), Key fingerprint: `5FD2 1B4F E7E4 A3CA 7971 CB09 DE66 3978 8E09 1026`* -----BEGIN PGP SIGNATURE----- iHUEARYIAB0WIQRf0htP5+SjynlxywneZjl4jgkQJgUCaeUiawAKCRDeZjl4jgkQ Js6HAQCnDctEMytr51mgBx3yyymD3ytjb8L9LKnydaZNJmGbpQD/SGZdJ6LfHmnB FRc0V336MNjqTFlaZvU0Wt4abYXy6gg= =rtqj -----END PGP SIGNATURE-----