EDR products have real blind spots, and understanding them is not a reason to distrust EDR, it is a reason to build layered coverage that compensates for those gaps. Every security control has limitations. Knowing where EDR coverage ends and where compensating controls need to start is what makes a defence programme mature rather than one that assumes a single tool provides complete coverage.
How EDR userland monitoring actually works
Most EDR products implement monitoring by injecting a DLL into every running process at startup. That DLL hooks sensitive Windows API functions by overwriting the first few bytes of each function with a JMP instruction that redirects execution through the EDR’s monitoring code before the real function runs. The EDR inspects the arguments, records the event, potentially blocks it, and then resumes execution of the original function. This is why EDR products can see API calls made by any process: their hook DLL is inside that process’s address space.
This architecture has two structural weaknesses. First, it operates entirely in userland. The kernel does not know or care about these hooks. Second, the hooks are just modified bytes in memory, sitting in the DLL that the EDR injected. Anything that can write to that memory can remove the hooks. Anything that bypasses userland entirely never triggers them at all.
Gap 1: direct syscalls bypass userland hooks entirely
Every Windows API function eventually calls a kernel function via a syscall instruction with a System Service Number (SSN). The SSN is just an integer that identifies which kernel function to call. Direct syscall techniques generate the syscall instruction and the correct SSN directly in attacker code, completely skipping the Windows API function and therefore completely skipping the EDR’s hook on that function.
; Direct syscall stub for NtOpenProcess
; Bypasses any userland hook on NtOpenProcess
NtOpenProcess_direct:
mov r10, rcx
mov eax, 0x26 ; SSN for NtOpenProcess on Win10 22H2
; This value varies by Windows version
; Tools like SysWhispers resolve it dynamically at runtime
syscall
ret
The defence against direct syscalls is kernel-level telemetry. The Microsoft-Windows-Threat-Intelligence ETW provider (ETWTI) captures these operations at the kernel level regardless of whether the userland hook fired. EDR products with kernel drivers consume this provider. To verify your EDR has kernel coverage run sc query type= kernel and look for your EDR vendor’s driver in the output. If it is not there, direct syscall operations are invisible to your endpoint monitoring.
Gap 2: process injection into excluded processes
EDR products maintain a list of processes they do not inject their hook DLL into. This list typically includes the EDR’s own processes, some system processes where injection would cause instability, and sometimes processes specified by the customer. The excluded list can sometimes be inferred by checking which running processes in your environment do not have the EDR hook DLL loaded in their module list.
# Check which processes do NOT have the EDR hook DLL loaded
# Replace 'edr_hook_dll.dll' with your actual EDR's DLL name
Get-Process | ForEach-Object {
$pid = $_.Id
$name = $_.Name
$modules = try { $_.Modules | Select-Object -ExpandProperty ModuleName } catch { @() }
if ('edr_hook_dll.dll' -notin $modules) {
Write-Output "No EDR hook: PID=$pid Name=$name"
}
}
Gap 3: early boot execution before EDR initialises
EDR agents are Windows services that start during the session manager phase of boot. Boot-start drivers (SERVICE_BOOT_START) load before any service. An attacker with the ability to install a boot-start driver can execute code before the EDR agent has initialised, before hooks are installed, and before any monitoring is active. Installing a malicious boot-start driver requires a kernel code signing certificate, which Secure Boot and Driver Signature Enforcement make difficult on modern systems. BYOVD (Bring Your Own Vulnerable Driver) circumvents this by exploiting a legitimately signed driver rather than loading an unsigned one.
Compensating controls for each gap
The response to each gap is a specific compensating control, not a wholesale rejection of EDR as a control. For direct syscall bypass: ensure your EDR has an active kernel driver consuming ETWTI. For injection into excluded processes: deploy Windows Defender Attack Surface Reduction rules, which operate at the kernel level independently of EDR userland hooks. For early boot execution: enable Secure Boot, enable UEFI firmware protection, and deploy the Microsoft Vulnerable Driver Blocklist to prevent BYOVD attacks that are commonly used to load malicious boot-start drivers.
Network monitoring is the most robust compensating control for all three gaps simultaneously. C2 traffic, lateral movement, and data exfiltration all generate network activity that is visible regardless of what happened on the endpoint. An attacker who successfully disables all endpoint monitoring still has to communicate over your network.