# Anti-Analysis Bypass Guide Reference for identifying and bypassing malware evasion techniques during dynamic analysis. --- ## Overview Anti-analysis techniques fall into four categories: | Category | Goal | MITRE ATT&CK | |----------|------|--------------| | VM/sandbox detection | Avoid executing in automated analysis environments | T1497 | | Debugger detection | Prevent live debugging and breakpoint analysis | T1622 | | Timing-based evasion | Delay execution past sandbox timeout windows | T1497.003 | | Environmental keying | Execute only when specific conditions are met | T1480 | --- ## VM and Sandbox Detection ### How Malware Detects VMs **Registry artifact checks (MITRE T1497.001):** ``` HKLM\SOFTWARE\Oracle\VirtualBox Guest Additions HKLM\SOFTWARE\VMware, Inc.\VMware Tools HKLM\SYSTEM\CurrentControlSet\Services\VBoxGuest HKLM\SYSTEM\CurrentControlSet\Services\vmhgfs HKLM\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0\Identifier → "VBOX HARDDISK", "VMWARE VIRTUAL IDE HARD DRIVE" ``` **Process enumeration:** ``` vboxservice.exe VirtualBox guest service vboxtray.exe VirtualBox system tray vmtoolsd.exe VMware Tools daemon vmwaretray.exe VMware system tray vmacthlp.exe VMware activation helper vmsrvc.exe VirtualPC service df5serv.exe Parallels service prl_tools.exe Parallels Tools ``` **Driver/device checks:** ``` \\.\VBoxMiniRdrDN \\.\VBoxGuest \\.\vmci \\.\HGFS \Device\VBoxGuest \Device\vmhgfs ``` **CPUID hypervisor bit (EAX=1, ECX bit 31):** Malware executes CPUID and checks bit 31 of ECX. If set, a hypervisor is present. Subsequent CPUID with EAX=0x40000000 returns a vendor string: "VMwareVMware", "KVMKVMKVM", "VBoxVBoxVBox", "Microsoft Hv". **MAC address OUI checks:** ``` 08:00:27 VirtualBox 00:0C:29 VMware 00:50:56 VMware (vSphere) 00:1C:14 VMware 00:05:69 VMware 00:03:FF Microsoft Hyper-V ``` **Screen resolution / user interaction:** ``` Screen size exactly 1024x768 → sandbox default No mouse movement history No browser history / recent files Uptime < 10 minutes Single CPU core Total RAM < 2 GB ``` **Identifying VM detection in static analysis:** Look for these API calls in import tables or dynamic calls: ``` GetSystemInfo → CPU count check GlobalMemoryStatusEx → RAM check EnumProcesses → process list scan CreateFile(\\.\) → device existence check RegOpenKeyEx / RegQueryValueEx → registry artifact checks GetAdaptersInfo → MAC address check GetTickCount / GetSystemTime → uptime / time checks ``` ### Bypass Strategies **Remove VirtualBox Guest Additions:** ```powershell # Uninstall via Control Panel or: Start-Process "C:\Program Files\Oracle\VirtualBox Guest Additions\uninstall.exe" -Wait # Remove leftover registry keys Remove-Item "HKLM:\SOFTWARE\Oracle\VirtualBox Guest Additions" -Recurse -ErrorAction SilentlyContinue Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\VBoxGuest" -Recurse -ErrorAction SilentlyContinue Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\VBoxSF" -Recurse -ErrorAction SilentlyContinue Remove-Item "HKLM:\SYSTEM\CurrentControlSet\Services\VBoxMouse" -Recurse -ErrorAction SilentlyContinue # Stop and delete VBox services sc.exe stop VBoxGuest sc.exe delete VBoxGuest ``` **Spoof BIOS/DMI strings (VirtualBox, run on host):** ```bash VBoxManage setextradata "VM-Name" \ "VBoxInternal/Devices/pcbios/0/Config/DmiBIOSVendor" "American Megatrends Inc." VBoxManage setextradata "VM-Name" \ "VBoxInternal/Devices/pcbios/0/Config/DmiBIOSVersion" "F10" VBoxManage setextradata "VM-Name" \ "VBoxInternal/Devices/pcbios/0/Config/DmiSystemProduct" "MS-7B86" VBoxManage setextradata "VM-Name" \ "VBoxInternal/Devices/pcbios/0/Config/DmiSystemVendor" "MSI" VBoxManage setextradata "VM-Name" \ "VBoxInternal/Devices/pcbios/0/Config/DmiBoardProduct" "MAG Z390 TOMAHAWK" VBoxManage setextradata "VM-Name" \ "VBoxInternal/Devices/pcbios/0/Config/DmiChassisVendor" "MSI" ``` **Suppress CPUID hypervisor bit (VirtualBox):** ```bash VBoxManage modifyvm "VM-Name" --paravirtprovider none ``` **VMware: suppress CPUID and hypervisor detection:** Add to the `.vmx` file: ``` hypervisor.cpuid.v0 = "FALSE" SMBIOS.reflectHost = "TRUE" board.vendor = "MSI" board.product = "MAG Z390 TOMAHAWK" ``` **Spoof MAC address:** ```bash # VirtualBox (use a real vendor OUI) VBoxManage modifyvm "VM-Name" --macaddress1 "8C8D28AABBCC" # Intel OUIs: 8C:8D:28, 00:1B:21, F4:4D:30 # Realtek OUI: 00:E0:4C ``` **Add realistic user artifacts:** ```powershell # Create browser history (requires Chrome installed) # Open URLs from PowerShell Start-Process "chrome.exe" "https://www.gmail.com" Start-Process "chrome.exe" "https://www.stackoverflow.com" # Create recent documents $docs = @("budget_2024.xlsx","notes.txt","presentation.pptx") foreach ($d in $docs) { New-Item -Path "$env:USERPROFILE\Documents\$d" -ItemType File -Force } # Set realistic uptime by running VM for 30+ minutes before analysis ``` **Use VBoxHardenedLoader (advanced):** VBoxHardenedLoader patches the VirtualBox kernel driver to pass CPUID and other checks transparently without removing guest additions. ``` # https://github.com/hfiref0x/VBoxHardenedLoader # Load driver: VBoxHLinstall.cmd # Provides transparent VM hiding while keeping shared folders functional ``` --- ## Debugger Detection ### How Malware Detects Debuggers (MITRE T1622) **IsDebuggerPresent / CheckRemoteDebuggerPresent:** Most common check. Reads the PEB (Process Environment Block) `BeingDebugged` flag directly. ``` PEB offset 0x2 (32-bit) / 0x2 (64-bit): BeingDebugged byte PEB offset 0x68 (32-bit) / 0xBC (64-bit): NtGlobalFlag (set to 0x70 under debugger) ``` **NtQueryInformationProcess:** ``` ProcessDebugPort (class 7) → non-zero if debugged ProcessDebugObjectHandle (class 30) → valid handle if debugged ProcessDebugFlags (class 31) → 0 if debugged ``` **Heap flags (PEB.ProcessHeap):** ``` Heap.Flags: normally 0x2, under debugger 0x50000062 Heap.ForceFlags: normally 0x0, under debugger 0x40000060 ``` **Hardware breakpoint detection:** Malware reads the debug registers DR0–DR3 via `GetThreadContext`. If any are non-zero, a hardware breakpoint is set. **Timing-based debugger detection:** ```c DWORD t1 = GetTickCount(); // execute a few instructions DWORD t2 = GetTickCount(); if ((t2 - t1) > threshold) { /* debugger detected */ } ``` When single-stepping in a debugger, even a few instructions take milliseconds vs. nanoseconds normally. **Exception-based detection:** Malware raises an exception (INT3, divide-by-zero) and checks if the debugger swallows it instead of passing it to the exception handler. **Window/process name enumeration:** ``` FindWindow("OLLYDBG", NULL) FindWindow("WinDbgFrameClass", NULL) FindWindow("ID", NULL) → Immunity Debugger FindWindow("Qt5QWindowIcon", NULL) → x64dbg EnumProcesses → scan for: ollydbg.exe, x32dbg.exe, x64dbg.exe, windbg.exe, ida.exe, ida64.exe, idag.exe, idaq.exe, immunitydebugger.exe, dnspy.exe, cheatengine.exe ``` ### Bypass Strategies **ScyllaHide (primary tool):** ScyllaHide is an anti-anti-debug plugin for x64dbg, OllyDbg, and IDA Pro. It patches all common detection methods transparently. ``` # Download: https://github.com/x64dbg/ScyllaHide # Install in x64dbg: # Copy ScyllaHide.dp32 / ScyllaHide.dp64 to x64dbg\plugins\ # Restart x64dbg # Plugins → ScyllaHide → Options # Enable all protections for evasive samples: [x] PEB BeingDebugged [x] PEB NtGlobalFlag [x] PEB HeapFlags [x] NtQueryInformationProcess [x] Unhandled Exception Handler [x] Hardware Breakpoint Protection [x] GetTickCount Hook [x] NtSetInformationThread ``` **TitanHide (kernel-level, for advanced evasion):** TitanHide is a kernel driver that hides debuggers at the OS level, defeating NtQueryInformationProcess and similar kernel-query-based checks. ``` # Download: https://github.com/mrexodia/TitanHide # Requires: Windows with test signing enabled or TESTSIGNING boot flag # Load driver: TitanHide.sys # Use x64dbg plugin interface for configuration ``` **Manual PEB patching in x64dbg:** ``` # In x64dbg, after attaching: # Open Memory Map → find PEB # Manually zero BeingDebugged byte: # 32-bit: # FS:[0x30] → PEB base # PEB+0x2 → BeingDebugged (set to 0x00) # PEB+0x68 → NtGlobalFlag (set to 0x00) # Use x64dbg script: mov byte ptr [peb()]:2, 0 # Clear BeingDebugged mov dword ptr [peb()]:0x68, 0 # Clear NtGlobalFlag ``` **Handle timing checks — NOP the sleep/delay:** ``` # In x64dbg, find GetTickCount/QueryPerformanceCounter calls # Identify the comparison instruction after the delta calculation # NOP the conditional jump (JNE, JA, JBE, etc.) # Or patch the threshold to an impossibly large value ``` **Handle exception-based detection:** ``` # In x64dbg: Options → Preferences → Exceptions # Add exception codes to "pass to program": # 0x80000003 (INT3 / STATUS_BREAKPOINT) # 0xC0000094 (divide by zero) # 0xC0000005 (access violation, if used as detection) ``` --- ## Timing-Based Evasion ### How Malware Uses Timing (MITRE T1497.003) **Sleep-based evasion:** Malware calls `Sleep(600000)` (10 minutes) or longer. Automated sandboxes that have a 2-5 minute timeout never observe the payload. ``` Sleep(DWORD dwMilliseconds) SleepEx(DWORD dwMilliseconds, BOOL bAlertable) WaitForSingleObject(HANDLE, INFINITE) NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval) ``` **Date/time checks:** Malware compares the current date against a hardcoded activation date. If before that date, it does nothing (making sandbox captures useless). If after an expiry date, it also does nothing (anti-forensics). **Idle/user activity checks:** ``` GetLastInputInfo() → returns milliseconds since last user input GetCursorPos() → called twice, checks if cursor moved GetForegroundWindow() → checks for active user window ``` If no mouse movement or keyboard input for N seconds, the malware assumes it is in a sandbox. ### Bypass Strategies **Patch Sleep calls in x64dbg:** ``` # Find calls to Sleep / SleepEx / NtDelayExecution # Option 1: NOP the entire Sleep call # Option 2: Patch the millisecond argument to 0 or 1 # In x64dbg, set a breakpoint on Sleep: # Breakpoints → Add → "Sleep" # When hit, change RCX (x64) or stack arg (x86) to 0 before continuing # x64dbg script to auto-patch: bp Sleep loopSleep: erun mov rcx, 0 // Zero the sleep duration (x64 first arg) erun goto loopSleep ``` **Accelerate sandbox clock (Cuckoo/CAPE):** ```yaml # In cuckoo.conf: [timeouts] critical = 60 vm_state = 60 # Enable clock skipping in analysis options: options: "clock=20200101120000" ``` **Manipulate system time on Windows VM:** ```powershell # Set date forward to trigger time-gated payloads Set-Date -Date "2025-06-15 12:00:00" # Use faketime (Linux / Wine) faketime '2025-06-15 12:00:00' wine sample.exe ``` **Simulate user activity:** ```powershell # Move mouse programmatically Add-Type -AssemblyName System.Windows.Forms while ($true) { $x = Get-Random -Minimum 100 -Maximum 1800 $y = Get-Random -Minimum 100 -Maximum 900 [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($x, $y) Start-Sleep -Milliseconds 500 } ``` **Extend sandbox timeout:** For CAPE/Cuckoo, increase the analysis timeout: ```bash python3 utils/submit.py --file sample.exe --timeout 300 ``` For manual analysis, simply wait — set observation window to 60+ minutes for suspected sleep-evasive samples. --- ## Environmental Keying ### How Malware Implements Environmental Checks (MITRE T1480) Environmental keying means the malware will only execute its payload if specific environmental conditions are met. This is distinct from VM detection — the malware is looking for a specific victim configuration. **Domain/hostname checks:** ``` GetComputerNameEx(ComputerNameDnsDomain, ...) NetGetJoinInformation() LookupAccountSid() → Malware may require a specific AD domain name or NETBIOS name ``` **Username checks:** ``` GetUserName() → compare against hardcoded victim username WNetGetUser() ``` **Installed software checks:** ``` HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ → enumerate installed apps HKLM\SOFTWARE\ → check for specific vendor keys ``` **Language/locale checks:** ``` GetSystemDefaultLangID() GetUserDefaultLCID() → Some malware won't run if locale is English or matches researcher's profile → Others skip execution if locale is Russian/Ukrainian (avoiding domestic prosecution) ``` **Network environment checks:** ``` GetAdaptersInfo() → check for specific IP ranges DnsQuery() → verify domain membership via DNS NetServerGetInfo() → check for domain controller presence ``` ### Bypass Strategies **Domain/hostname spoofing:** ```powershell # Change computer name (requires restart) Rename-Computer -NewName "WORKSTATION-01" -Force # Join a fake workgroup matching expected domain name # (Does not require actual domain controller) Add-Computer -WorkgroupName "TARGETCORP" ``` **Username spoofing:** ```powershell # Create a user matching expected victim name New-LocalUser -Name "jsmith" -NoPassword Add-LocalGroupMember -Group "Administrators" -Member "jsmith" # Log in as that user, then execute sample ``` **Locale patching:** ``` # In x64dbg, break on GetSystemDefaultLangID / GetUserDefaultLCID # Patch EAX return value to match expected locale # Russian: 0x0419, Romanian: 0x0418, Ukrainian: 0x0422 ``` **Registry keying bypass:** ``` # If malware checks for a specific product registry key: # Identify the expected key via static analysis (strings, IDA) # Create a fake registry entry before execution: New-Item -Path "HKLM:\SOFTWARE\TargetVendor\TargetProduct" -Force New-ItemProperty -Path "HKLM:\SOFTWARE\TargetVendor\TargetProduct" ` -Name "Version" -Value "1.0" -PropertyType String ``` --- ## Tools for Anti-Analysis Bypass ### ScyllaHide Purpose: Plugin for x64dbg, OllyDbg, IDA Pro, TitanHide. Patches all common anti-debug checks transparently. ``` Download: https://github.com/x64dbg/ScyllaHide/releases Platforms: x32dbg, x64dbg, OllyDbg 1.10, OllyDbg 2.01, IDA Pro Install: Copy DLL to debugger plugins folder Key options: - PEB patch (BeingDebugged, NtGlobalFlag, HeapFlags) - NtQueryInformationProcess hooks - Timing hooks (GetTickCount, QueryPerformanceCounter) - NtSetInformationThread (hide from debugger) - Unhandled exception fix ``` ### TitanHide Purpose: Kernel-mode driver that hides debugger presence from NtQueryInformationProcess and related syscalls. ``` Download: https://github.com/mrexodia/TitanHide Requires: Windows with test signing or driver certificate Use case: When ScyllaHide user-mode hooks are insufficient (malware uses direct syscalls to bypass user-mode hooks) ``` ### al-khaser Purpose: Open-source tool that tests over 170 anti-analysis checks. Use to validate VM hardening before analyzing evasive samples. ``` Download: https://github.com/LordNoteworthy/al-khaser Build: Visual Studio solution (.sln) Run: al-khaser.exe Output: Pass/fail for each check category: - Anti-VM - Anti-debug - Anti-sandbox - Anti-disassembly - Timing ``` ### pafish Purpose: Lightweight VM/sandbox detection tester. Faster than al-khaser for quick pre-analysis validation. ``` Download: https://github.com/a0rtega/pafish/releases Run: pafish.exe Green: Check passed (not detected) Red: Check failed (artifact detected — fix before analyzing evasive samples) ``` ### hollows_hunter / pe-sieve Purpose: Scan a running process for injected code, hollowed sections, and unpacked payloads in memory. Useful after malware defeats initial analysis controls. ``` Download: https://github.com/hasherezade/hollows_hunter Run: hollows_hunter.exe /pid Output: Dumps hollowed/injected regions to disk for static analysis ``` ### x64dbg Plugins for Anti-Analysis ``` ScyllaHide Anti-debug bypass (essential) xAnalyzer Extended analysis and comment generation xHotConvert Quick conversion utilities OllyDumpEx Process dumper for unpacking ``` --- ## Identifying Anti-Analysis at a Glance During static analysis, flag these patterns for targeted bypass: **String indicators:** ``` "IsDebuggerPresent" → debugger detection "CheckRemoteDebugger" → remote debugger detection "NtQueryInformationProcess" → advanced debugger/VM detection "VBOX", "VMWARE", "QEMU", "VIRTUAL" → VM string checks "GetTickCount" → timing-based detection "GetLastInputInfo" → user interaction check "GetSystemDefaultLangID" → locale-based keying "GetComputerName" → hostname keying "EnumProcesses" → process-list scanning ``` **Import table red flags:** ``` kernel32.dll: IsDebuggerPresent, CheckRemoteDebuggerPresent, GetTickCount, QueryPerformanceCounter, GetLastInputInfo, GetCursorPos ntdll.dll: NtQueryInformationProcess, NtSetInformationThread, NtDelayExecution, RtlQueryProcessHeapInformation advapi32.dll: RegOpenKeyEx (combined with SYSTEM\CurrentControlSet\Services) iphlpapi.dll: GetAdaptersInfo (MAC address check) ``` **Behavioral indicators during dynamic analysis:** ``` Process exits immediately (< 2 seconds) → VM or debugger detected No network activity despite expected C2 → sandbox/network detection Sleep calls with long durations (> 30s) → timing evasion Repeated GetTickCount/RDTSC in tight loop → timing check CreateFile on \\.\VBoxGuest or \\.\vmci → device probing ``` --- ## MITRE ATT&CK Reference | Technique | ID | Description | |-----------|-----|-------------| | Virtualization/Sandbox Evasion | T1497 | Parent technique | | System Checks | T1497.001 | Registry, filesystem, hardware artifacts | | User Activity Based Checks | T1497.002 | Mouse movement, input, idle time | | Time Based Evasion | T1497.003 | Sleep calls, date checks, RDTSC | | Debugger Evasion | T1622 | IsDebuggerPresent, NtQueryInformationProcess | | Execution Guardrails | T1480 | Environmental keying, domain/locale checks | | Obfuscated Files or Information | T1027 | Packed/encrypted payloads that unpack in memory | --- ## Analysis Decision Tree ``` Sample exits immediately? ├─ Yes → Check: is VM artifact present? → Fix VM hardening, retry │ Check: debugger detected? → Enable ScyllaHide, retry │ Check: locale/domain check? → Spoof environment, retry └─ No → Sample is executing No network activity? ├─ Check: INetSim running and configured? ├─ Check: DNS resolving to INetSim IP? ├─ Check: malware performing HTTPS certificate pinning? │ → Use Proxifier + mitmproxy to intercept └─ Check: malware waiting for sleep delay? → Patch Sleep calls, extend timeout Behavior stops after initial activity? ├─ Check: C2 response expected? → Configure INetSim response templates ├─ Check: time-gated payload? → Advance system clock └─ Check: requires second-stage download? → Serve fake C2 response via INetSim ```