This is a technical look at EDR coverage gaps identified during controlled testing in a lab environment. The goal is not to provide a bypass guide but to give defenders a concrete understanding of where their tooling has blind spots so those
gaps can be addressed with complementary controls.
Test environment
Windows 10 22H2 VM with two common commercial EDR products installed (not named — the categories of gaps apply broadly, not to specific vendors). All tests conducted against the VM itself using custom tooling written specifically for this
research rather than published offensive tools, to avoid signature-based catches complicating the results.
Gap 1: Userland hook bypass via direct syscalls
Most EDR products inject a DLL (commonly called a “hook DLL” or “injection DLL”) into every process. This DLL overwrites the first few bytes of sensitive NTAPI functions like NtCreateProcess, NtWriteVirtualMemory, and
NtOpenProcess with a JMP instruction that redirects execution to the EDR’s monitoring code before the actual function runs.
The bypass: rather than calling the Windows API, call the kernel directly using the syscall instruction with the correct System Service Number (SSN). The SSN for each function can be resolved by parsing ntdll.dll from disk (the on-disk copy is
unhooked) or using techniques like Hell’s Gate that read SSNs from memory by locating unhooked adjacent functions.
A minimal direct syscall stub for NtOpenProcess looks like:
; NTSTATUS NtOpenProcess(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID)
NtOpenProcess:
mov r10, rcx ; syscall convention
mov eax, 0x26 ; SSN for NtOpenProcess on Win10 22H2
syscall
ret
In testing, memory operations performed via direct syscalls were not detected by either EDR product. The operations appear in kernel ETW traces (Microsoft-Windows-Threat-Intelligence provider) but Sysmon-only deployments and EDRs that rely
solely on userland hooks will miss them entirely.
Defensive response: Ensure your EDR uses a kernel driver component, not just userland injection. Verify this by checking whether !process 0 0 in a kernel debugger shows an EDR-related kernel driver loaded. If your
EDR only shows up as a DLL in process listings and has no kernel driver, your coverage against direct syscall techniques is limited.
Gap 2: Early boot execution before EDR initialisation
EDR agents register as Windows services and load after the kernel and core system processes. The typical EDR service start type is SERVICE_AUTO_START, which means it starts during the session manager phase of boot — but several
things start before it.
Specifically, Boot Start drivers (SERVICE_BOOT_START) and System Start drivers (SERVICE_SYSTEM_START) load before any auto-start services. If an attacker can install a malicious boot-start driver (which requires kernel
code signing on modern Windows — a significant barrier, but not impossible with a leaked or stolen certificate), it can execute before the EDR is loaded and establish hooks that intercept or modify EDR behaviour.
A less privileged variant: certain COM objects and scheduled tasks configured to run at user logon execute before the EDR agent fully initialises its monitoring hooks. In testing, a scheduled task set to run at logon with a 0-second delay
executed and completed before EDR coverage was active for that session.
Gap 3: Process injection into EDR-excluded processes
EDR products typically exclude themselves and certain system processes from injection and monitoring to avoid self-interference and performance issues. The excluded process list can sometimes be inferred by checking which running processes do
not have the EDR hook DLL loaded:
// Check which processes are missing the EDR hook DLL
for each process in running_processes:
modules = EnumProcessModules(process.handle)
if "edr_hook.dll" not in modules:
candidate_processes.append(process)
In testing, injecting into processes on the exclusion list produced no EDR telemetry for the injected code’s subsequent actions.
Compensating controls
None of these gaps means EDR is not worth having. The point is layered coverage. Specific additions that close the above gaps:
- Enable the Microsoft-Windows-Threat-Intelligence ETW provider via a kernel driver — this catches direct syscall operations that bypass userland hooks
- Enable Secure Boot and UEFI firmware protection to raise the bar on boot-start driver attacks
- Deploy Attack Surface Reduction rules in Windows Defender, which run at the kernel level independently of EDR userland hooks
- Network monitoring catches C2 traffic regardless of how the process executing it evaded endpoint detection