What is Process Injection?#

In essence, process injection involves:

Inserting a block of code (usually shellcode) into the memory space of a process.

Process injection is a means to an end for evading on disk detection. Instead of executing malicious code directly via a PE file or script (which could more easily be caught on disk by antivirus or EDR), the code is injected into process memory.

While by no means is this a reliably stealthy on its own, it is a fundamental concept needed to be understood before developing more advanced execution workflows.


High Level Workflow:#

The process injection workflow typically will follow a rough pattern of:

  1. Identify Target Process
  • The loader finds or spawns a remote process (e.g., notepad.exe).
  • The loader may sometimes inject code into it’s own process.
    • This is from what I’ve noticed more opsec friendly
  1. Open Handle
  • The injector uses OpenProcess() to get a handle to the target process.
  1. Allocate Memory
  • Using VirtualAllocEx(), the injector reserves space in the target process.
  1. Write Payload
  • The payload (e.g., shellcode) is copied using WriteProcessMemory().
  1. Execute Payload
  • A new thread is created in the remote process using CreateRemoteThread() or similar.

OpenProcess(), VirtuallAllocEx(), WriteProcessMemory(), and CreateRemoteThread are all low level functions exposed via the Windows API, which in this case facilitate interacting with memory space within the Windows Operating system.

A term you will here often when discussing malware is “Shellcode”. Shellcode is malicious machine code (not human readable) with the intent of either spawning a command shell, or otherwise executing what would be considered malicious activities. Machine code is simply naively written code in the language the host CPU can interpret.

The perk here is that this code is suitable to be injected directly into memory. Attackers will typically convert their post exploitation tooling into shellcode in order for it to be prepared for memory injection

Shellcode features include:

  • Machine code: Shellcode is written in low-level machine code, not a human-readable language like C or Python.
  • Compact: It is designed to be small and efficient to fit within the limitations of the exploit.
  • Platform-specific: Shellcode is typically written for a specific architecture (e.g., x86, ARM) and operating system (e.g., Windows, Linux).

Upfront OpSec Considerations#

While shellcode injection can absolutely can assist in stealthy malicious code execution, it is not perfect on its own. The injection workflow being rather predictable gives modern tooling such as EDR (Endpoint Detection and Response) an advantage, being that these leverage heuristics that have becoming increasingly competent at detecting unusual and malicious behavior.

Some traditional antivirus solutions will include basic memory monitoring and forensics capabilities, and do not solely rely on detecting what is on disk.

Detection is typical based on:

  • Memory Forensics:
    • Unusual memory permissions (e.g., RWX).
    • Injected code in non-module memory regions.
    • Signature malicious memory content.
  • Process Behavior:
    • Child processes with suspicious parent-child relationships.
    • Unexpected threads in common processes.
  • Logging Tools:
    • Sysmon (Event ID 8, 10, 11).
    • ETW (Event Tracing for Windows).
    • AMSI logs (for script-based loaders).
    • EDR software.

However a little TLC using basic encryption and obfuscation routines, memory injection routines can bypass traditional antivirus quite effectively.

And with some forward and outside the box thinking, bypassing EDR is always still possible.


Real-World Use Cases#

In order to run further post exploitation activities, malicious actors and Red Teamers like myself will often have to rely on using “loaders” to load their tooling into memory via process injecting techniques. We will typically need to attempt to obfuscate, encrypt, or otherwise disguise their injected shellcode to avoid memory detections, while simultaneously attempting to disguise the loaders malicious behavior to avoid heuristic detection. It is no small potatoes, but it is what it takes to get code execution in the modern landscape.

An example goal using process injection as a means to an end for could be injecting a C2 beacon:

A defender bypass using RC4 encrypted Sliver C2shellcode, injected into the loaders own process memory


An EDR bypass leveraging process injection via indirect system calls, and custom written encrypted shellcode dumping credentials out of a web browser.

Debuggers and defensive tooling themselves also will routinely rely on process injection techniques, as it can be a legitimate and normal process for benign software to sometimes also rely on. Softwares such as EDRs even.

What’s Next?#

In one of the the next blog posts, we’ll explore a real-world example of PowerShell-based process injection, showing how to:

  • Spawn a process
  • Inject shellcode
  • Execute a remote thread
  • And analyze detection techniques