Take the File Away
On-disk evasion fights the file engine. In-memory evasion refuses the fight.
The idea: never write the payload to disk at all. Build it and run it entirely in memory. You can’t scan a file that was never created, so the most aggressive engine in the AV has nothing to do.
This is where modern malware lives, and it’s the more powerful of the two families.
Process Injection
The signature in-memory technique is process injection: smuggle your shellcode into a legitimate process and run it from there.
The classic version is a four-step dance using Windows APIs:
OpenProcessgets a handle to a process you’re allowed to touchVirtualAllocExcarves out a fresh block of memory inside that processWriteProcessMemorycopies your shellcode into itCreateRemoteThreadruns it
Your code now executes inside a process the AV trusts. There’s no malicious file on disk, and the running code wears a legitimate process’s name.
There are stealthier variants of the same idea:
| Technique | The trick |
|---|---|
| Reflective DLL injection | Load a DLL straight from memory (normal loading only works from disk) |
| Process hollowing | Start a legit process suspended, gut its code, swap in yours, resume it |
| Inline hooking | Patch a function in memory so it detours through your code first |
Inline hooking is a favorite of rootkits, the stealthiest malware. They patch system components in user space, the kernel, or even lower, which is why they need admin privileges to install.
Rename and Walk Past
Here’s how trivially signature detection can break, even for an in-memory technique.
A common move is to run the injection from a PowerShell script instead of a compiled binary. Why? A script is just interpreted text. It has no rigid executable structure to fingerprint, and if AV flags it, you can change it and rerun without recompiling anything.
The script imports VirtualAlloc, CreateThread, and memset, allocates memory, writes the shellcode in, and runs it, all inside the current PowerShell process.
But the first version often gets caught anyway. Scanned against many AV products, a textbook injection script might be flagged by roughly half of them.
Why? Because to catch malicious scripts, AV relies on static string signatures: it matches meaningful names in the code, like the class name and the variable names.
The fix is almost insultingly simple. Rename them to something generic:
| Original | Renamed |
|---|---|
Win32 | iWin32 |
$sc | $var1 |
$winFunc | $var2 |
Rescan, and the script comes back clean. The signature was matching on names, and you changed the names.
The signature matched the labels, not the behavior. Nothing about what the script does changed. This is the whole game in miniature: AV recognizes what it has seen, so make it look unseen.
One operational gotcha: PowerShell’s Execution Policy may block the script first (“running scripts is disabled on this system”). It’s a per-user setting, not a security boundary:
Set-ExecutionPolicy Unrestricted -Scope CurrentUserOr sidestep it per-run with -ExecutionPolicy Bypass. Note that Active Directory Group Policy can lock this down harder.
The Arms Race
Step back and the whole field is one feedback loop:
- Vendors build signatures from samples they collect
- Attackers make their code novel so there’s no sample to match
- Vendors counter with heuristics, sandboxes, and ML that don’t need an exact match
- Attackers counter with in-memory execution and legitimate-process disguises
Each side forces the other to get more sophisticated.
AV recognizes what it has already seen. That one fact is both the weakness you exploit and the reason evasion is never permanently solved. Today’s clean payload is tomorrow’s signature.
Practice Boxes
- Abusing Windows Internals - Process injection and hollowing through the Windows API. Maps almost 1:1 to this note.
- Runtime Detection Evasion - Bypass AMSI and other in-memory runtime checks.