Introduction
The Problem: Repetitive allocations are a detection goldmine
- NtAllocateVirtualMemory is called once for the function-map table and once per COFF section (.text, .data, .rdata, etc.)
- The raw section bytes are copied into the freshly allocated regions
- Relocations and symbol resolution are processed
- NtProtectVirtualMemory is called to transition the ‘.text’ section from ‘PAGE_READWRITE’ to ‘PAGE_EXECUTE_READ’
- The entry point is called
- Output is captured
- Every allocated region is freed via NtFreeVirtualMemory
What EDRs See
- Usermode hooks on critical NT APIs (NtAllocateVirtualMemory, NtProtectVirtualMemory, NtFreeVirtualMemory) allow the EDR to intercept each allocation, protection change, and free operation. Even when these hooks are bypassed through indirect syscalls or unhooking, the kernel-level telemetry remains.
- Kernel callbacks and ETW (Event Tracing for Windows) provide an independent layer of visibility. The kernel can observe:
– Memory allocation events: new committed regions appearing in the process address space
– Protection change events: the ‘RW ⇒ RX’ transition on the ‘.text’ section is a high-signal indicator
– The allocation pattern itself: multiple ‘MEM_COMMIT | MEM_RESERVE’ calls in rapid succession for small, similarly-sized regions - Memory scanning is often triggered by behavioral signals. When an EDR observes a suspicious pattern (e.g., a new RX region that didn’t come from a loaded DLL), it may perform a synchronous or asynchronous scan (mostly yara) of the process memory looking for known signatures.
- Behavioral correlation ties these signals together. A single NtAllocateVirtualMemory call is not inherently suspicious. But when the EDR’s ring-buffer correlates dozens of allocation-protect-execute-free cycles happening from the same thread, in the same process, over a short window, it paints a clear picture of in-memory module loading: a behavior that is almost exclusively associated with offensive tooling.
The Solution: Load Once, Execute Many, Unload When Done
- Load the ZOF binary into a persistent memory region once.
- Encrypt it at rest.
- On each execution: decrypt ⇒ set proper protections ⇒ execute ⇒ restore to RW and re-encrypt
- Optional: unload explicitly when the module is no longer needed
Introducing coffee load, coffee mem, and coffee unload
With the latest ZAIUX® Framework release, we introduce Persistent In-Memory Module Loading, a new execution model for ZOF (Zaiux Object Files) that decouples memory allocation from module execution through three new commands: coffee load, coffee mem, and coffee unload.
coffee load <file> <alias> uploads a ZOF binary into the implant’s process memory under a unique operator-defined alias. The raw COFF is written into a single PAGE_READWRITE region, immediately encrypted at rest, and tracked in a persistent linked list. From this point forward, the module exists in memory as high-entropy data indistinguishable from ordinary heap content: no executable permissions, no recognizable COFF structures.
coffee mem <alias> [args...] executes a previously loaded module without allocating new memory for the binary itself. The encrypted blob is decrypted in-place, sections and relocations are processed onto pre-allocated regions within the same allocation, the ‘.text’ section is briefly transitioned to PAGE_EXECUTE_READ for execution, output is captured, and the entire region is restored to PAGE_READWRITE and re-encrypted. Called without arguments, coffee mem lists all currently loaded modules with their alias, address, and size.
coffee unload <alias> performs a clean removal: the encrypted region is zeroed, freed via NtFreeVirtualMemory and the tracking node is unlinked from the list.

The operational benefit is a direct reduction in observable telemetry. A module executed 20 times through the traditional coffee command produces 100 NtAllocateVirtualMemory and 100 NtFreeVirtualMemory calls. The same 20 executions through coffee load + coffee mem produce exactly 1 allocation and 1 free, the rest happens on already-committed memory. This collapses the behavioral signal that EDR correlation engines rely on: fewer allocation events, no repeated RW-to-RX transitions on new regions, and no allocation-free cycles clustering in sliding detection windows.