Avanzadoanti-debuganti-VManti-sandboxevasionreverse engineeringanalisis avanzado

Tecnicas Anti-Analisis: Anti-Debug, Anti-VM y Anti-Sandbox

Tecnicas anti-analisis en malware: IsDebuggerPresent, timing checks, deteccion de VM via CPUID y MAC, deteccion de sandbox, evasion de analisis automatizado. Contramedidas y bypass para cada tecnica.

MalwareIntel Research··11 min lectura
Serie: Análisis de Binarios — Parte 14

La carrera armamentista del analisis

El malware sofisticado no se limita a hacer dano: antes verifica si esta siendo observado. Las tecnicas anti-analisis son la tercera capa de defensa del malware, despues del packing y la ofuscacion. Mientras el packer oculta el codigo y la ofuscacion lo hace ilegible, las tecnicas anti-analisis detectan el entorno de analisis y modifican el comportamiento del malware.

Un malware con anti-debug puede parecer benigno en un debugger. Un malware con anti-VM puede no ejecutar su payload en las maquinas virtuales que usan las sandboxes automatizadas. Y un malware con anti-sandbox puede esperar minutos antes de hacer nada, agotando el timeout del analisis automatizado.

Entender estas tecnicas y sus contramedidas es fundamental para el reverse engineering efectivo.

Tecnicas Anti-Debug

IsDebuggerPresent

La tecnica mas basica. Llama a la API IsDebuggerPresent de kernel32.dll, que simplemente lee el campo BeingDebugged del PEB (Process Environment Block):

; Equivalente manual
mov eax, fs:[0x30]     ; PEB
movzx eax, byte [eax+2] ; PEB.BeingDebugged
test eax, eax
jnz debugger_detected

Contramedida:

  • En x64dbg: ir a PEB (usando dump fs:[0x30]), cambiar byte en offset +2 a 0.
  • Plugin ScyllaHide en x64dbg: parchea automaticamente IsDebuggerPresent.
  • En IDA: poner breakpoint en IsDebuggerPresent y cambiar el valor de retorno (EAX) a 0.

CheckRemoteDebuggerPresent

Verifica si un debugger remoto esta adjunto al proceso:

BOOL bDebuggerPresent = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &bDebuggerPresent);
if (bDebuggerPresent) exit(0);

Contramedida: Hookear la funcion para que siempre escriba FALSE. ScyllaHide lo maneja automaticamente.

NtQueryInformationProcess

Consulta informacion del proceso con diferentes clases de informacion:

// ProcessDebugPort (0x07)
DWORD debugPort = 0;
NtQueryInformationProcess(
    GetCurrentProcess(), 7, &debugPort, sizeof(debugPort), NULL
);
if (debugPort != 0) exit(0);

// ProcessDebugObjectHandle (0x1E)
HANDLE debugObject = NULL;
NtQueryInformationProcess(
    GetCurrentProcess(), 0x1E, &debugObject, sizeof(debugObject), NULL
);
if (debugObject != NULL) exit(0);

// ProcessDebugFlags (0x1F)
DWORD debugFlags = 0;
NtQueryInformationProcess(
    GetCurrentProcess(), 0x1F, &debugFlags, sizeof(debugFlags), NULL
);
if (debugFlags == 0) exit(0);  // 0 = debugger presente

Contramedida: ScyllaHide hookea NtQueryInformationProcess para las tres clases de informacion.

PEB.NtGlobalFlag

Cuando un proceso se crea bajo un debugger, el campo NtGlobalFlag del PEB se establece con flags de heap debugging:

; Verificar NtGlobalFlag
mov eax, fs:[0x30]     ; PEB
mov eax, [eax + 0x68]  ; PEB.NtGlobalFlag (offset 0x68 en x86)
and eax, 0x70          ; FLG_HEAP_ENABLE_TAIL_CHECK |
                        ; FLG_HEAP_ENABLE_FREE_CHECK |
                        ; FLG_HEAP_VALIDATE_PARAMETERS
jnz debugger_detected

Contramedida: Parchear el campo NtGlobalFlag a 0 en el PEB.

Timing Checks

Medir el tiempo de ejecucion de un bloque de codigo. Bajo debugging paso a paso, el tiempo es enormemente mayor:

// RDTSC (Read Time-Stamp Counter)
unsigned __int64 time1, time2;
time1 = __rdtsc();
// ... codigo trivial ...
time2 = __rdtsc();
if ((time2 - time1) > 1000000) exit(0);  // threshold

// GetTickCount
DWORD t1 = GetTickCount();
// ... codigo ...
DWORD t2 = GetTickCount();
if ((t2 - t1) > 100) exit(0);

// QueryPerformanceCounter
LARGE_INTEGER t1, t2;
QueryPerformanceCounter(&t1);
// ... codigo ...
QueryPerformanceCounter(&t2);
if ((t2.QuadPart - t1.QuadPart) > threshold) exit(0);

Contramedida:

  • Evitar single-stepping en bloques con timing: poner breakpoint despues del bloque.
  • Parchear la instruccion RDTSC para que retorne un valor fijo.
  • ScyllaHide puede parchear RDTSC.

Deteccion de breakpoints

Software breakpoints (INT 3):

// Verificar si hay INT 3 (0xCC) en una funcion
unsigned char* func = (unsigned char*)&target_function;
for (int i = 0; i < 100; i++) {
    if (func[i] == 0xCC) exit(0);  // breakpoint detectado
}

Hardware breakpoints (debug registers):

// Leer debug registers via GetThreadContext
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(GetCurrentThread(), &ctx);
if (ctx.Dr0 || ctx.Dr1 || ctx.Dr2 || ctx.Dr3) {
    exit(0);  // hardware breakpoints activos
}

Contramedida:

  • Para software BPs: usar hardware breakpoints en su lugar.
  • Para hardware BPs: hookear GetThreadContext para limpiar los debug registers.

Exception-based anti-debug

El malware genera una excepcion intencionalmente. Si hay un debugger, este la captura. Si no hay debugger, el handler de excepciones del malware se ejecuta normalmente:

__try {
    __asm { int 0x2D }  // Genera excepcion
    // Si llegamos aqui, hay debugger (absorbi la excepcion)
    exit(0);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
    // Normal: sin debugger, la excepcion fue manejada aqui
    continue_execution();
}

Contramedida: Configurar el debugger para pasar la excepcion al programa. En x64dbg: Options, Exceptions, pasar INT 2D al programa.

Tecnicas Anti-VM

CPUID: Hypervisor Brand String

La instruccion CPUID con EAX=1 retorna feature flags. El bit 31 de ECX indica si se ejecuta en un hypervisor:

; Verificar hypervisor bit
mov eax, 1
cpuid
bt ecx, 31        ; Hypervisor present bit
jc vm_detected

; Obtener brand string del hypervisor (EAX=0x40000000)
mov eax, 0x40000000
cpuid
; ECX:EDX:EBX contiene el brand string
; "VMwareVMware" = VMware
; "Microsoft Hv" = Hyper-V
; "KVMKVMKVM" = KVM
; " lrXenXenXen" = Xen
; "VBoxVBoxVBox" = VirtualBox

Contramedida: Configurar la VM para ocultar el hypervisor:

# VMware: en .vmx
hypervisor.cpuid.v0 = "FALSE"
cpuid.1.ecx = "---0----:--------:--------:--------"

# VirtualBox:
VBoxManage modifyvm "VM" --paravirtprovider none
VBoxManage setextradata "VM" "VBoxInternal/CPUM/IsaExts/HYPERVISOR" 0

MAC Address

Los adaptadores de red virtuales usan rangos de MAC conocidos:

Prefijo MACProducto
00:0C:29VMware
00:50:56VMware
08:00:27VirtualBox
00:1C:14VMware (Player)
00:15:5DHyper-V
52:54:00QEMU/KVM
// Verificar MAC address
GetAdaptersInfo(...)
if (mac[0]==0x00 && mac[1]==0x0C && mac[2]==0x29) vm_detected();  // VMware

Contramedida: Cambiar la MAC del adaptador virtual a un rango de hardware real.

Registro de Windows

El malware busca claves de registro especificas de VMs:

ClaveProducto
HKLM\SOFTWARE\VMware, Inc.\VMware ToolsVMware
HKLM\SOFTWARE\Oracle\VirtualBox Guest AdditionsVirtualBox
HKLM\HARDWARE\ACPI\DSDT\VBOXVirtualBox
HKLM\HARDWARE\Description\System "SystemBiosVersion" contiene VBOXVirtualBox
HKLM\HARDWARE\Description\System "SystemBiosVersion" contiene VMWAREVMware

Contramedida: Eliminar o renombrar estas claves de registro en la VM de analisis.

Procesos y servicios de VM

Proceso / ServicioProducto
vmtoolsd.exeVMware Tools
vmwaretray.exeVMware Tray
VBoxService.exeVirtualBox Guest Additions
VBoxTray.exeVirtualBox Tray
xenservice.exeXen Guest Agent
// Buscar procesos de VM
CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
Process32First/Next()
if (strcmp(process_name, "vmtoolsd.exe") == 0) vm_detected();

Contramedida: Renombrar los ejecutables de guest additions o no instalarlos (sacrificando funcionalidad).

Hardware fingerprinting

VerificacionIndicador de VM
Tamano de discoMenor a 60-80 GB
RAMMenor a 4 GB
Numero de CPUs1 solo core
Resolucion de pantalla800x600 o dimensiones inusuales
Dispositivos USBNinguno conectado
ImpresorasNinguna instalada
Archivos recientesDirectorio vacio
Programas instaladosMuy pocos programas

Contramedida: Configurar la VM con recursos realistas: minimo 4 GB RAM, 2 cores, disco de 100+ GB, resolucion 1920x1080, y algunos programas instalados para simular un sistema real.

Tecnicas Anti-Sandbox

Delay execution

La mayoria de sandboxes tienen un timeout (2 a 5 minutos). El malware puede esperar antes de ejecutar su payload:

// Sleep largo
Sleep(300000);  // 5 minutos

// Alternativas a Sleep que son mas dificiles de hookear
// 1. Loop de NtDelayExecution
// 2. WaitForSingleObject con timeout
// 3. SetTimer + MsgWaitForMultipleObjects
// 4. Loop computacionalmente intensivo

// Loop de calculo para gastar tiempo sin llamar a Sleep
volatile int x = 0;
for (int i = 0; i < 1000000000; i++) {
    x = x + i * 3;
}

Contramedida:

  • Hookear Sleep/NtDelayExecution para reducir el delay a 0.
  • Las sandboxes modernas (ANY.RUN, Joe Sandbox) parchean Sleep automaticamente.
  • Algunos sandboxes aceleran el reloj del sistema.

User interaction checks

El malware verifica que haya actividad de usuario real:

// Verificar movimiento del mouse
POINT p1, p2;
GetCursorPos(&p1);
Sleep(2000);
GetCursorPos(&p2);
if (p1.x == p2.x && p1.y == p2.y) sandbox_detected();

// Verificar historial de navegador
// Un sistema real tiene historial; una sandbox limpia no

// Verificar documentos recientes
// CSIDL_RECENT con archivos = sistema real

// Verificar numero de procesos
// Un sistema real tiene 50+ procesos; una sandbox puede tener pocos

Contramedida: Sandboxes interactivas como ANY.RUN permiten mover el mouse y hacer click manualmente. Algunas sandboxes automatizan la interaccion.

Environment checks

// Verificar nombre del equipo
GetComputerName()
// Sandboxes comunes: "DESKTOP-ABC123", "WIN-SANDBOX", "JOHN-PC"

// Verificar nombre de usuario
GetUserName()
// Sandboxes: "admin", "user", "sandbox", "malware", "analyst"

// Verificar dominio
GetComputerNameEx(ComputerNameDnsDomain)
// Sandboxes: no suelen estar en dominio

// Verificar zona horaria
GetTimeZoneInformation()
// Algunos malware solo se ejecuta en la zona horaria del objetivo

Sandbox-specific artifacts

El malware busca artefactos de sandboxes conocidas:

ArtefactoSandbox
SbieDll.dll cargadaSandboxie
dbghelp.dll, api_log.dllCWSandbox
pstorec.dllSunBelt Sandbox
vmcheck.dllVirtual PC
cmdvrt32.dllComodo Sandbox
Proceso cuckoomon.dllCuckoo Sandbox
C:\analysisMultiples sandboxes

ScyllaHide: el bypass universal

ScyllaHide es un plugin para x64dbg (y OllyDbg) que parchea automaticamente la mayoria de tecnicas anti-debug:

Protecciones que bypasea:

  • IsDebuggerPresent / CheckRemoteDebuggerPresent
  • NtQueryInformationProcess (ProcessDebugPort, DebugObjectHandle, DebugFlags)
  • PEB.BeingDebugged, PEB.NtGlobalFlag
  • Heap flags (HeapFlags, ForceFlags)
  • OutputDebugString
  • NtSetInformationThread (HideFromDebugger)
  • NtClose (handle tracing)
  • RDTSC timing
  • GetTickCount
  • Hardware breakpoint hiding
  • NtYieldExecution

Configuracion en x64dbg: Plugins, ScyllaHide, Options, seleccionar las protecciones a habilitar.

Tabla resumen: tecnicas y contramedidas

TecnicaTipoContramedida
IsDebuggerPresentAnti-debugScyllaHide, parchear PEB
NtQueryInformationProcessAnti-debugScyllaHide, hook NtQIP
RDTSC timingAnti-debugScyllaHide, parchear RDTSC
INT 3 scanningAnti-debugUsar hardware breakpoints
Debug registersAnti-debugHook GetThreadContext
Exception-basedAnti-debugPasar excepciones al programa
CPUID hypervisorAnti-VMOcultar hypervisor en config VM
MAC addressAnti-VMCambiar MAC a rango real
VM registry keysAnti-VMEliminar claves de VM
VM processesAnti-VMNo instalar guest additions
SleepAnti-sandboxHookear Sleep, acelerar reloj
Mouse checkAnti-sandboxSandbox interactiva
User/Computer nameAnti-sandboxNombres realistas
Disk/RAM sizeAnti-sandboxRecursos realistas

Script de deteccion de anti-analisis

import pefile
import sys

ANTI_DEBUG_APIS = [
    "IsDebuggerPresent",
    "CheckRemoteDebuggerPresent",
    "NtQueryInformationProcess",
    "OutputDebugStringA",
    "OutputDebugStringW",
    "GetTickCount",
    "QueryPerformanceCounter",
    "GetThreadContext",
    "SetUnhandledExceptionFilter",
    "NtSetInformationThread",
    "NtClose",
    "CloseHandle",
]

ANTI_VM_APIS = [
    "GetAdaptersInfo",
    "EnumDeviceDrivers",
    "GetDiskFreeSpaceEx",
    "GlobalMemoryStatusEx",
    "GetSystemInfo",
]

ANTI_SANDBOX_APIS = [
    "GetCursorPos",
    "GetForegroundWindow",
    "Sleep",
    "GetComputerName",
    "GetUserName",
    "GetModuleHandle",
]

def detect_anti_analysis(filepath):
    pe = pefile.PE(filepath)

    anti_debug = []
    anti_vm = []
    anti_sandbox = []

    if hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
        for entry in pe.DIRECTORY_ENTRY_IMPORT:
            for imp in entry.imports:
                if imp.name:
                    name = imp.name.decode()
                    if name in ANTI_DEBUG_APIS:
                        anti_debug.append(name)
                    if name in ANTI_VM_APIS:
                        anti_vm.append(name)
                    if name in ANTI_SANDBOX_APIS:
                        anti_sandbox.append(name)

    print("=== Anti-Analysis Detection Report ===")
    print("File:", filepath)
    print()

    if anti_debug:
        print("Anti-Debug APIs found:")
        for api in anti_debug:
            print("  [!] " + api)

    if anti_vm:
        print("\nAnti-VM APIs found:")
        for api in anti_vm:
            print("  [!] " + api)

    if anti_sandbox:
        print("\nAnti-Sandbox APIs found:")
        for api in anti_sandbox:
            print("  [!] " + api)

    total = len(anti_debug) + len(anti_vm) + len(anti_sandbox)
    if total == 0:
        print("No anti-analysis APIs detected in static imports.")
        print("Note: APIs may be resolved dynamically at runtime.")
    elif total > 5:
        print("\n[!] Alto numero de APIs anti-analisis detectadas")
        print("    Probable evasion activa")

if __name__ == "__main__":
    detect_anti_analysis(sys.argv[1])

Preparacion del entorno de analisis

Para minimizar la deteccion por parte del malware:

  1. VM realista: Minimo 4 GB RAM, 2+ cores, disco 100+ GB, resolucion 1920x1080.
  2. Software instalado: Office, navegador con historial, cliente de email, algunos archivos en Documentos.
  3. Guest additions: Instalar pero renombrar ejecutables.
  4. Red: Configurar red NAT o host-only, pero con resolucion DNS funcional.
  5. Usuario realista: Nombre de usuario y computadora plausibles.
  6. Plugins anti-anti-debug: ScyllaHide en x64dbg.
  7. Snapshots: Siempre tener un snapshot limpio antes de ejecutar muestras.
  8. Aislamiento: La VM de analisis nunca debe tener acceso a la red corporativa.

Conclusion

Las tecnicas anti-analisis son una carrera armamentista: los autores de malware implementan nuevos checks, los analistas desarrollan bypasses, y el ciclo continua. El analista efectivo conoce las tecnicas comunes, mantiene un entorno de analisis configurado para minimizar la deteccion, y usa herramientas como ScyllaHide para parchear automaticamente los checks mas comunes.

La regla practica: si un malware detecta el entorno de analisis y se cierra, no es el fin del analisis. Es una pista: el malware tiene algo que ocultar, y las tecnicas anti-analisis que usa (y como las implementa) son en si mismas indicadores valiosos para la clasificacion y atribucion.

Preguntas frecuentes

Artículos relacionados

Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.