Module 5: Sandbox Detection & Process Protection
Know your environment before you act — eight checks to detect analysis sandboxes, plus techniques to harden your process against inspection.
Why Sandbox Detection Matters
Modern AV and EDR products don't just scan files statically — they execute suspicious binaries inside virtual machine sandboxes to observe runtime behavior. These sandboxes record API calls, network traffic, file system changes, and memory operations. If your loader runs its full payload inside a sandbox, the AV engine captures its entire behavioral signature. Sandbox detection allows the loader to recognize when it is running inside an analysis environment and exit cleanly before revealing any malicious behavior.
The Sandbox Problem
Sandboxes are purpose-built analysis VMs. They share common characteristics that distinguish them from real workstations: low resource allocation (RAM, CPU, disk), generic hostnames and usernames, specific virtualization drivers, and the presence of analysis tools. Hooka exploits these artifacts through eight distinct detection functions, each targeting a different sandbox fingerprint. Individually, each check has false-positive potential — but combined, they provide high-confidence detection.
Hooka's Eight Sandbox Detection Checks
Each check function returns a boolean: true if the environment appears to be a sandbox, false if it looks like a real machine. All nine are defined in pkg/hooka/sandbox.go.
1. CheckMemory()
RAM Size Detection
Sandboxes typically allocate minimal RAM to their analysis VMs — often 2–4 GB. Real workstations in 2024 almost always have 8 GB or more. CheckMemory() queries the total physical memory via GlobalMemoryStatusEx and flags environments with less than 4 GB of RAM as probable sandboxes.
Gofunc CheckMemory() (bool, error) {
// Uses GlobalMemoryStatusEx to get total physical RAM
// Returns true if RAM < 4GB (sandbox indicator)
}
2. CheckDisk()
Disk Size Detection
Analysis VMs use thin-provisioned disks that are often 40–80 GB. Production machines almost always have 100 GB+. CheckDisk() calls GetDiskFreeSpaceExW on the system drive and flags disks smaller than 100 GB total capacity.
3. CheckInternet()
Network Connectivity Check
Many sandboxes run in isolated network environments without internet access to prevent malware from reaching C2 infrastructure. CheckInternet() attempts an HTTP connection to a known-good external endpoint. Failure to connect suggests an isolated sandbox environment.
4. CheckHostname()
Hostname Pattern Matching
Sandbox VMs frequently use default or generic hostnames. CheckHostname() retrieves the machine hostname via os.Hostname() and compares it against a list of known sandbox hostname patterns:
WIN-*andDESKTOP-*with random suffixesSANDBOX,MALWARE,VIRUSJOHN-PC,TEQUILABOOMBOOM- Other common sandbox default names
5. CheckUsername()
Username Pattern Matching
Similar to hostname checks, sandboxes often run under predictable usernames. CheckUsername() retrieves the current user via os.Getenv("USERNAME") and checks against known sandbox defaults:
admin,administrator,usermalware,sandbox,virustest,sample,analyst
6. CheckCpu()
CPU Core Count
Sandboxes allocate minimal CPU resources — often a single core or two. CheckCpu() queries the processor count via runtime.NumCPU() and flags systems with fewer than 2 cores as likely VMs. Most physical workstations have 4+ cores.
7. CheckDrivers()
Virtualization Driver Detection
Hypervisors install specific drivers that are visible from within the guest. CheckDrivers() enumerates loaded drivers and checks for signatures from common virtualization platforms:
| Platform | Driver Names |
|---|---|
| VMware | vmci.sys, vmhgfs.sys, vmmouse.sys, vmrawdsk.sys |
| VirtualBox | VBoxMouse.sys, VBoxGuest.sys, VBoxSF.sys, VBoxVideo.sys |
| Hyper-V | vmbus.sys, VMBusHID.sys, hyperkbd.sys |
8. CheckProcess()
Analysis Tool Detection
If analysis tools are running, the environment is almost certainly being monitored. CheckProcess() enumerates running processes via CreateToolhelp32Snapshot and looks for known analysis and debugging tools:
- Network analysis:
wireshark.exe,tcpdump.exe,fiddler.exe - Process monitoring:
procmon.exe,procexp.exe,processhacker.exe - Debuggers:
x64dbg.exe,x32dbg.exe,ollydbg.exe,windbg.exe,ida.exe,ida64.exe - Sandbox agents:
vmsrvc.exe,vboxservice.exe,vmtoolsd.exe
9. AutoCheck() — The Combined Check
All Checks Combined
AutoCheck() is the master function that runs all eight checks above in sequence. If any single check returns true, AutoCheck considers the environment a sandbox and returns true. This is what the CLI --sandbox flag invokes internally.
Gofunc AutoCheck() (bool, error) {
// Runs all 8 checks sequentially
// Returns true if ANY check detects a sandbox
// Returns false only if ALL checks pass
}
The fail-fast approach means the loader exits at the first sign of sandbox activity. This minimizes the behavioral footprint observed by the analysis engine.
Sandbox Check Decision Tree
When the --sandbox flag is enabled, the generated loader runs this decision flow at startup before any injection occurs:
AutoCheck() Execution Flow
Loader begins
Run all 8 checks
Any check true?
os.Exit(0)
Proceed to injection
Execution Environment Validation
Beyond sandbox detection, Hooka can restrict execution to specific target machines. This ensures the loader only runs on the intended host, not on analyst workstations or unrelated systems.
Target Restriction Flags
| Flag | Purpose | How It Works |
|---|---|---|
--user <name> | Restrict by username | Compares os.Getenv("USERNAME") against the specified value. If mismatch, the loader exits silently. |
--computername <name> | Restrict by hostname | Compares os.Hostname() against the specified value. If mismatch, the loader exits silently. |
These flags are particularly useful in targeted operations where you know the exact username and hostname of the target machine. If the loader lands on the wrong system (analyst VM, wrong workstation), it exits without executing any payload.
Bash# Only execute on the target machine "CORP-WS-042" as user "jsmith"
hooka -i shellcode.bin -o loader.exe --user jsmith --computername CORP-WS-042
Arbitrary Code Guard (ACG)
ACG is a Windows mitigation policy that prevents a process from generating or modifying executable code at runtime. This directly interferes with how AV/EDR products inject monitoring DLLs into processes.
How ACG Protects Your Process
When ACG is enabled via SetProcessMitigationPolicy, the following operations are blocked for the calling process:
- Allocating new executable memory (
PAGE_EXECUTE_*viaVirtualAlloc) - Changing existing memory to executable (
VirtualProtecttoPAGE_EXECUTE_*) - Mapping executable memory-mapped files
This prevents AV/EDR engines from injecting their monitoring hooks into the process after ACG is enabled. The trick is that the loader enables ACG after its own shellcode is already mapped and executable, but before AV has a chance to inject.
Go// EnableACG activates Arbitrary Code Guard for the current process
func EnableACG() error {
// Calls SetProcessMitigationPolicy with ProcessDynamicCodePolicy
// Sets ProhibitDynamicCode = 1
// After this call, no new executable memory can be created
}
ACG Timing Is Critical
ACG must be enabled after your shellcode has been placed in executable memory but before EDR products attempt to inject their hooks. If enabled too early, it will block your own shellcode from being mapped. If enabled too late, the EDR hooks are already in place. The CLI flag --acg inserts the call at the correct point in the startup sequence.
Block Non-Microsoft DLLs
EDR products typically inject monitoring DLLs into every new process. The PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY flag can prevent DLLs not signed by Microsoft from loading into a process.
BlockDLLs() — Self-Protection
BlockDLLs() applies the DLL blocking policy to the current process. It calls NtSetInformationProcess with ProcessMitigationPolicy to enable the PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON flag. After this call, any attempt to load a DLL that is not signed by Microsoft will fail.
CreateProcessBlockDLLs(cmd) — Spawn Protected Process
CreateProcessBlockDLLs(cmd) creates a new process with DLL blocking enabled from the start. It uses CreateProcessW with an extended startup info structure containing the mitigation policy attribute. This is particularly useful when spawning a sacrificial process for injection — the target process is protected from EDR DLL injection from the moment it starts.
Go// CreateProcessBlockDLLs spawns a new process with non-MS DLL blocking
func CreateProcessBlockDLLs(cmd string) (*windows.ProcessInformation, error) {
// 1. Initialize STARTUPINFOEX with PROC_THREAD_ATTRIBUTE_LIST
// 2. Set PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY
// 3. Enable BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON
// 4. CreateProcessW with EXTENDED_STARTUPINFO_PRESENT
}
Bash# Generate a loader with DLL blocking enabled
hooka -i shellcode.bin -o loader.exe --blockdlls
Phant0m — Event Log Suppression
Windows Event Logging records security-relevant events (process creation, logon events, privilege escalation). The Phant0m technique suppresses logging by suspending all threads of the Event Log service.
How Phant0m Works
- GetEventLogPid() locates the PID of the Windows Event Log service (
svchost.exehostingEventLog) by enumerating services viaEnumServicesStatusExWand finding the one with service name "EventLog". - Phant0m(pid) takes the Event Log PID, enumerates all of its threads using
CreateToolhelp32SnapshotwithTH32CS_SNAPTHREAD, and suspends each thread viaSuspendThread.
With all threads suspended, the Event Log service is alive but cannot process or write any events. No crash, no restart — just silence.
Go// Step 1: Find the Event Log service PID
pid, err := hooka.GetEventLogPid()
// Step 2: Suspend all threads in the Event Log process
err = hooka.Phant0m(pid)
Operational Considerations
Phant0m does not delete existing logs — it only prevents new events from being recorded. The suspended threads can be resumed by an administrator or a system restart. Some EDR products monitor the Event Log service's health and may alert if its threads are suspended. The CLI flag --phantom enables this technique in the generated loader.
Custom Sleep for Time-Based Evasion
Sandboxes impose time limits on analysis — typically 30–120 seconds. If a sample doesn't exhibit malicious behavior within that window, the sandbox moves on. Conversely, some sandboxes detect calls to Sleep() or WaitForSingleObject() and fast-forward time.
Hooka's Sleep() Function
Hooka implements a custom sleep mechanism that delays execution without using the obvious kernel32.Sleep API. This serves two purposes:
- Time-based evasion: delays execution past the sandbox's analysis window
- API-level stealth: avoids hooking on the standard
Sleepfunction
The --sleep CLI flag inserts a sleep call at the very beginning of the loader's execution, before any sandbox checks or injection occurs.
Go// Sleep delays execution using an alternative timing mechanism
func Sleep() {
// Uses alternative wait method to avoid Sleep() API hooks
// Typical delay: several seconds to minutes
// Placed at the very start of loader execution
}
Protection Techniques Comparison
| Technique | Function | CLI Flag | Defends Against |
|---|---|---|---|
| Sandbox Detection | AutoCheck() | --sandbox | AV sandbox behavioral analysis |
| User Restriction | Environment check | --user | Execution on wrong target machine |
| Host Restriction | Environment check | --computername | Execution on analyst workstation |
| ACG Guard | EnableACG() | --acg | Post-injection EDR code injection |
| Block DLLs | BlockDLLs() | --blockdlls | EDR monitoring DLL injection |
| Phant0m | Phant0m(pid) | --phantom | Windows Event Log recording |
| Custom Sleep | Sleep() | --sleep | Time-based sandbox analysis |
Combining Protections
In practice, you layer multiple protections. The generated loader applies them in a specific order that maximizes effectiveness:
Protection Startup Sequence
Time delay
AutoCheck()
Validate target
Patch defenses
Clean NTDLL
Harden process
Payload exec
Maximum Protection CLI Example
Bash# Enable all protective measures
hooka -i shellcode.bin -o loader.exe \
--sandbox \
--user targetuser \
--computername CORP-WS-042 \
--acg \
--blockdlls \
--phantom \
--sleep
This generates a loader that sleeps first, then validates the sandbox, user, and hostname, patches AMSI/ETW, unhooks NTDLL, enables ACG and DLL blocking, suppresses event logging, and only then proceeds with shellcode injection.
Module 5 Quiz: Sandbox Detection & Process Protection
Q1: What does AutoCheck() return if CheckMemory() detects <4 GB RAM but all other checks pass?
Q2: Why must ACG (Arbitrary Code Guard) be enabled AFTER shellcode is mapped to memory?
Q3: What does the Phant0m technique do to the Windows Event Log service?