Skip to main content
20 min read Beginner Desktop

Process Injection: A Beginner's Guide to the Techniques and the Basics Behind Them

A step-by-step guide that starts from how Windows runs processes and ends with the main process injection techniques, how they work, and how defenders detect them. No prior knowledge of Windows internals is needed.

Level: Beginner to Intermediate. Focus: Windows.

This guide is for authorized red team work, malware analysis, and defensive research. Only run these techniques against systems you own or have written permission to test. Injecting code into other people's processes without permission is illegal in most places.

Process injection is a family of techniques for running your code inside another running program. Attackers use it to hide, to steal data, and to get past security tools. Defenders need to understand it to detect it. Red teamers use it during authorized engagements. This guide explains the building blocks first, then walks through each technique.


Part 1: Setting the Scene

What Is Process Injection?

Process injection means placing code into the memory of another process and getting that process to run it. The code then runs with the identity and permissions of the target process, not your own.

Attackers do this for a few reasons:

  • Hiding. Malicious activity looks like it comes from a trusted program such as explorer.exe or svchost.exe.
  • Bypassing controls. Some security tools trust certain processes, so code running inside them draws less attention.
  • Access. Running inside a target process gives access to that process's memory, handles, and network connections.
  • Persistence and privilege. Injecting into a higher-privilege process can raise the attacker's access level.

Why Learn It

If you defend systems, you cannot detect what you do not understand. Most modern malware and most red team tools use some form of injection. If you do authorized offensive testing, injection is a core skill for staying quiet and reaching your goal.

Where It Sits in an Attack

Injection is usually a middle step, not the first one. The attacker already has code running (for example from a phishing document or a dropped file). Injection is how they move that code into a better host process to run more quietly or with more access.


Part 2: The Windows Basics You Need First

Injection makes sense only once you know a few core ideas. Take these one at a time.

Processes

A process is a running program. When you launch notepad.exe, Windows creates a process for it. Each process gets:

  • Its own private virtual memory space.
  • One or more threads that actually run code.
  • A set of handles to resources such as files and other objects.
  • A security token that says who the process runs as and what it can do.

One key point: a process is mostly a container. It holds memory and resources. It does not run code by itself. Threads do that.

Threads

A thread is the unit that actually runs instructions. A process has at least one thread, and can have many. Each thread has:

  • Its own stack.
  • Its own set of CPU register values, saved when the thread is not running. This saved set is called the thread context.
  • A current instruction pointer, which is the address of the next instruction it will run.

Injection almost always comes down to one goal: get a thread in the target process to run your code. You can do this by creating a new thread, hijacking an existing one, or queueing work onto one.

Virtual Memory

Each process has its own private virtual address space. Addresses in one process do not point to the same data in another process. This is why you cannot just write to another process's memory directly. You have to ask the operating system to do it for you, through special functions.

Memory in a process has protection flags that say what you can do with each region:

  • Read
  • Write
  • Execute

For example, PAGE_EXECUTE_READWRITE means a region can be read, written, and run as code. Code that can be both written and executed is a classic sign of injection, because normal program code is usually not writable.

Handles

A handle is a reference to a system object, such as a process, thread, or file. To act on another process you first open a handle to it. The handle you get is limited by access rights. For example, to write to another process's memory you need a handle opened with rights that allow it.

Access Tokens and Privileges

A token describes the security identity of a process: the user, the groups, and the privileges. Some injection techniques need a special privilege called SeDebugPrivilege, which lets a process open almost any other process. Administrators can enable it. This is why running as admin makes many injection techniques easier.

DLLs

A DLL (Dynamic Link Library) is a file of code that a process can load and use at runtime. Windows itself is built from DLLs such as kernel32.dll and ntdll.dll. A common injection goal is to force a target process to load a DLL you control. Once loaded, the DLL's startup code runs inside the target.

The Windows API Layers

When code calls a Windows function, the call usually passes through layers:

Your program
|
kernel32.dll / kernelbase.dll (documented Win32 API, for example VirtualAllocEx)
|
ntdll.dll (native API, for example NtAllocateVirtualMemory)
|
system call into the kernel

Most injection uses the documented Win32 functions in kernel32.dll. More advanced or stealthy tools call the lower ntdll.dll functions directly to skip security hooks placed on the higher layer. Knowing these layers exist helps you understand both attacks and detection.


Part 3: The Core Building Blocks

Almost every classic injection technique is built from the same small set of API calls. Learn these five and you will recognize most techniques.

StepWin32 functionWhat it does
1. Open the targetOpenProcessGet a handle to the target process with the rights you need
2. Allocate memoryVirtualAllocExReserve a region of memory inside the target
3. Write your dataWriteProcessMemoryCopy your code or DLL path into that region
4. Set permissionsVirtualProtectExMark the region executable if needed
5. Run itCreateRemoteThreadStart a new thread in the target that runs your code

The lower-level ntdll.dll equivalents are NtOpenProcess, NtAllocateVirtualMemory, NtWriteVirtualMemory, NtProtectVirtualMemory, and NtCreateThreadEx. Same idea, one layer down.

The differences between injection techniques mostly come down to two questions:

  1. How do you get your code into the target's memory.
  2. How do you get a thread to run it.

Everything else is a variation on those two.


Part 4: The Types of Process Injection

Here is the landscape. Each type is explained in more detail below the table.

TechniqueHow code gets inHow it runsNotes
Classic DLL injectionWrite a DLL path, call LoadLibraryNew remote threadSimple, well known, easy to detect
Reflective DLL injectionWrite the whole DLL, load it manuallyNew remote threadNo DLL on disk, no LoadLibrary
PE injectionWrite a full executable imageNew remote threadSelf-contained, no file on disk
Process hollowingStart a process suspended, replace its imageResume the main threadMalware looks like a trusted program
Thread execution hijackingWrite code, point an existing thread at itRedirect a suspended threadNo new thread created
APC injectionWrite code, queue it to a threadRuns when the thread goes alertableIncludes the Early Bird variant
SetWindowsHookExLoad a DLL via a message hookRuns on the hooked eventNeeds a message-driven target
AppInit_DLLsRegistry value lists a DLLLoaded by every GUI processLegacy, mostly blocked now
Atom bombingStore code in the global atom tableAPC runs itOlder, evasion focused
Process doppelgangingLoad an image from a transacted fileRuns the crafted sectionAbuses NTFS transactions
Process ghosting / herpaderpingAlter or delete the file before it runsRuns the crafted sectionConfuses tools that read the file later
Module stompingOverwrite a legit loaded DLL in memoryRuns from a trusted moduleHides code inside a real module

Classic DLL Injection

This is the simplest and most common technique. The idea is to make the target process load a DLL you control.

Steps:

  1. Open a handle to the target with OpenProcess.
  2. Allocate memory in the target with VirtualAllocEx.
  3. Write the full path to your DLL into that memory with WriteProcessMemory.
  4. Create a remote thread with CreateRemoteThread, and set its start function to LoadLibraryA, with the argument being the address of the DLL path you wrote.

Because LoadLibraryA lives at the same address in every process (kernel32 is loaded at the same base in a given boot session), you can pass its address directly. When the remote thread runs LoadLibrary("C:\\path\\evil.dll"), the target loads your DLL and runs its startup code.

// Illustrative outline, not a complete program.
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPid);

// 1. allocate memory in the target for the DLL path
LPVOID remoteBuf = VirtualAllocEx(hProc, NULL, pathLen,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

// 2. write the DLL path into the target
WriteProcessMemory(hProc, remoteBuf, "C:\\path\\evil.dll", pathLen, NULL);

// 3. find LoadLibraryA in kernel32 (same address in the target)
LPVOID loadLib = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");

// 4. create a thread in the target that calls LoadLibraryA(remoteBuf)
CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)loadLib,
remoteBuf, 0, NULL);

Strengths: simple and reliable. Weaknesses: the DLL must exist on disk, and the pattern of VirtualAllocEx plus WriteProcessMemory plus CreateRemoteThread pointing at LoadLibrary is one of the most watched patterns in security tools.

Reflective DLL Injection

Classic injection needs the DLL on disk, which leaves a file for defenders to find. Reflective DLL injection avoids this.

Instead of writing a path and calling LoadLibrary, the attacker writes the entire DLL file into the target's memory, then runs a small piece of loader code that does what LoadLibrary would do: map the sections, fix up addresses, resolve imports, and call the entry point. The Windows loader is never asked to load the DLL, so there is no file on disk and no standard load event.

This is stealthier because it skips LoadLibrary and leaves nothing on disk. It is harder to write because the loader logic must be included in the DLL itself.

PE Injection

PE injection is similar in spirit. Instead of a DLL, the attacker copies a full executable image (a PE, Portable Executable) into the target and runs it there. The injected image is written directly into the target's memory and executed with a new thread. Like reflective injection, nothing needs to be on disk.

Process Hollowing (also called RunPE)

Process hollowing makes a malicious program appear to be a trusted one. The steps are:

  1. Start a legitimate program in a suspended state, for example CreateProcess("svchost.exe", CREATE_SUSPENDED). The process exists but its main thread has not run yet.
  2. Unmap (hollow out) the original image from the process's memory.
  3. Write the malicious image into that space.
  4. Point the process's entry point at the new image.
  5. Resume the main thread. The process now runs the malicious code, but its name, path, and command line still say it is the trusted program.
Before: [ svchost process, suspended, original image loaded ]
Step: hollow out the original image
After: [ svchost process, malicious image loaded, resumed ]
still shows up as svchost.exe in Task Manager

This is popular because the process looks legitimate to a casual look. Detection focuses on the mismatch between the file on disk and the code actually running in memory.

Thread Execution Hijacking

Instead of creating a new thread, this technique takes over one that already exists. Creating a remote thread is a watched event, so reusing an existing thread can be quieter.

Steps:

  1. Open the target and find a thread in it.
  2. Suspend that thread with SuspendThread.
  3. Read its current registers with GetThreadContext.
  4. Write your code into the target's memory.
  5. Change the saved instruction pointer to point at your code with SetThreadContext.
  6. Resume the thread with ResumeThread. It now runs your code first.

The core idea is that a thread's context includes its instruction pointer. If you change it while the thread is suspended, the thread runs wherever you point it when it resumes.

APC Injection

APC stands for Asynchronous Procedure Call. Windows lets you queue a function to run on a specific thread. The queued function runs the next time that thread enters an alertable state, which happens when it calls certain waiting functions.

Steps:

  1. Write your code into the target's memory.
  2. Get a handle to a thread in the target.
  3. Queue your code onto that thread with QueueUserAPC.
  4. When the thread becomes alertable, it runs your code.
// Illustrative outline.
LPVOID remoteBuf = VirtualAllocEx(hProc, NULL, codeLen,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProc, remoteBuf, shellcode, codeLen, NULL);
QueueUserAPC((PAPCFUNC)remoteBuf, hThread, 0);

A well-known variant is Early Bird APC injection. The attacker creates a process in a suspended state, queues an APC to its main thread, and then resumes it. The APC runs very early, before many security hooks are in place, which makes it harder to catch.

SetWindowsHookEx

Windows lets a program install a hook that runs code in response to events such as keystrokes or window messages. SetWindowsHookEx can load a DLL into other processes that receive those messages. An attacker installs a hook backed by a malicious DLL, and the DLL gets loaded into target processes when the hooked events occur. This works best against processes that have a message loop, such as GUI applications.

AppInit_DLLs

This is a legacy Windows feature. A registry value named AppInit_DLLs lists DLLs that get loaded into almost every process that uses user32.dll. Setting it to a malicious DLL causes wide loading. It is mostly historical now, because modern Windows disables it when Secure Boot is on, but you may still see it referenced.

Atom Bombing

The global atom table is a shared area where processes can store small pieces of string data. Atom bombing stores attacker code as atom data, then uses an APC to get the target to read that data back and run it. It was notable because it used only legitimate Windows features and avoided the usual suspicious calls. It is older now and well documented for detection.

Process Doppelganging

This technique abuses NTFS transactions, a feature that lets file changes be grouped and rolled back. The attacker creates a file inside a transaction, writes malicious content, creates a memory section from it, and then rolls the transaction back so the file never really lands on disk in its malicious form. The process is created from the crafted section. Security tools that scan the file on disk see nothing wrong, because the malicious version was never committed.

Process Ghosting and Herpaderping

These are related tricks that confuse tools which read a process's backing file after it starts.

  • Process ghosting: the file is marked for deletion before the process is created from it, so by the time a tool tries to read it, the file is gone.
  • Process herpaderping: the file's contents are changed after the image is mapped but before the process runs, so the file on disk no longer matches the code in memory.

Both aim to break the assumption that the file on disk equals the code that is running.

Module Stomping

Also called module overloading. The attacker gets the target to load a legitimate, signed DLL, then overwrites that DLL's code in memory with malicious code. The malicious code now runs from inside what looks like a trusted, signed module, which helps it blend in.


Part 5: A Simple Mental Model

If the list feels long, group the techniques by the two questions from Part 3.

How does the code get in:

  • Point to a DLL on disk and load it (classic DLL injection, SetWindowsHookEx, AppInit_DLLs).
  • Write the whole payload into memory (reflective DLL, PE injection, most shellcode methods).
  • Replace or overwrite an existing image (process hollowing, module stomping).
  • Use a file trick so the on-disk view is wrong (doppelganging, ghosting, herpaderping).

How does it run:

  • Create a new thread (classic, reflective, PE injection).
  • Reuse an existing thread (thread hijacking, APC, atom bombing).
  • Resume a suspended process at the new code (hollowing, Early Bird, doppelganging).

Almost every technique is one choice from each list.


Part 6: How Defenders Detect Injection

Understanding detection makes the techniques clearer, and it is the point of the exercise for defenders.

Common signals:

  • API call patterns. OpenProcess then VirtualAllocEx then WriteProcessMemory then CreateRemoteThread is a classic sequence. Endpoint tools watch for it.
  • Remote thread creation. A thread created in a process by a different process is unusual and is logged (for example Sysmon event ID 8).
  • Memory that is both writable and executable. Regions marked PAGE_EXECUTE_READWRITE, especially ones not backed by a file on disk, are suspicious.
  • Image and file mismatch. When the code running in memory does not match the file on disk, that points to hollowing, doppelganging, or herpaderping.
  • Unbacked executable memory. Executable memory that has no matching file (private memory running code) is a strong signal, since normal code runs from mapped image files.
  • Unusual parent and child relationships. A document reader spawning a suspended system process is a red flag.
  • Calls into ntdll that skip the usual higher-layer hooks, which can indicate direct syscall use.

Useful tools for study and detection:

  • Sysmon, for logging process creation, remote threads, and image loads.
  • Process Hacker or System Informer, for viewing memory regions and their protection flags.
  • Moneta and pe-sieve, for scanning a process for injected or unbacked code.
  • Volatility, for finding injection in a full memory capture.
  • A debugger such as WinDbg or x64dbg, for watching the injection happen step by step.

Summary

  • Process injection means running your code inside another process, so it runs with that process's identity and access.
  • The basics you need are processes (containers of memory and resources), threads (which run code and have a context with an instruction pointer), virtual memory (private per process, with read, write, and execute flags), handles (references to objects), tokens (security identity), and DLLs (loadable code).
  • Most classic techniques are built from five calls: OpenProcess, VirtualAllocEx, WriteProcessMemory, VirtualProtectEx, and CreateRemoteThread, or their ntdll equivalents.
  • Every technique answers two questions: how the code gets into the target, and how a thread runs it.
  • Techniques range from simple classic DLL injection to hollowing, thread hijacking, APC, and file-based tricks such as doppelganging and ghosting.
  • Defenders detect injection through API call patterns, remote thread creation, writable and executable memory, and mismatches between the file on disk and the code in memory.

Practical Appendix: Injection Techniques at a Glance

This appendix summarizes each technique in a fixed format. Each entry has the Key APIs, a short Description, and a Detection note. It is split into two collapsible sections: memory-write techniques and image or file techniques.

Note: the expand and collapse blocks below use <details> HTML. They work on GitHub, GitLab, VS Code, and most static site tools. Medium does not support them, so on Medium treat each summary line as a subheading.

Section A: Memory-Write and Thread-Based Techniques

These write code or a DLL reference into a target and then get a thread to run it.

A1. Classic DLL injection

Key APIs

OpenProcess -> VirtualAllocEx -> WriteProcessMemory -> CreateRemoteThread(LoadLibraryA)

Description

Write the path to a DLL into the target, then create a remote thread that calls LoadLibraryA on that path. The target loads and runs your DLL. Simple and reliable, but the DLL must exist on disk.

Detection

The allocate, write, create-remote-thread sequence pointing at LoadLibrary is heavily monitored. A DLL file on disk is also available for scanning.

A2. Reflective DLL injection

Key APIs

VirtualAllocEx -> WriteProcessMemory (whole DLL) -> CreateRemoteThread (custom loader)

Description

Write the entire DLL into the target's memory, then run a small custom loader that maps sections, fixes addresses, resolves imports, and calls the entry point. LoadLibrary is never used and no file is on disk.

Detection

Look for unbacked executable memory (executable private memory with no matching file) and for a remote thread starting inside a private region.

A3. PE injection

Key APIs

VirtualAllocEx -> WriteProcessMemory (full PE image) -> CreateRemoteThread

Description

Copy a full executable image into the target and run it there. Self-contained, needs nothing on disk. Similar to reflective injection but for a full program image rather than a DLL.

Detection

Unbacked executable memory and a remote thread whose start address is in private memory.

A4. Thread execution hijacking

Key APIs

OpenThread -> SuspendThread -> GetThreadContext -> WriteProcessMemory -> SetThreadContext -> ResumeThread

Description

Take over an existing thread instead of creating one. Suspend it, change its saved instruction pointer to point at your code, then resume it. No new thread is created, which can be quieter.

Detection

Watch for GetThreadContext and SetThreadContext against threads in another process, and for a thread's instruction pointer landing in private, executable memory.

A5. APC injection (including Early Bird)

Key APIs

VirtualAllocEx -> WriteProcessMemory -> QueueUserAPC (-> ResumeThread for Early Bird)

Description

Queue your code as an Asynchronous Procedure Call onto a target thread. It runs when the thread becomes alertable. The Early Bird variant queues the APC to a suspended new process and resumes it, so the code runs very early, before many defenses are ready.

Detection

QueueUserAPC targeting a thread in another process, especially right after a process is created in a suspended state.

A6. SetWindowsHookEx

Key APIs

LoadLibrary (local) -> SetWindowsHookEx -> (hook fires in target)

Description

Install a message hook backed by a malicious DLL. Processes that receive the hooked events load the DLL. Works best against GUI processes that have a message loop.

Detection

Unusual global hooks and a DLL being loaded into many processes at once.

A7. Atom bombing

Key APIs

GlobalAddAtom -> NtQueueApcThread -> (target reads atom and runs it)

Description

Store code in the global atom table, then use an APC to make the target read the data back and run it. Notable for using only legitimate features and avoiding the usual write-to-remote-memory calls.

Detection

APC activity combined with atom table use, and code running from unexpected memory. Well documented for modern tools.


Section B: Image Replacement and File-Based Techniques

These replace a process image or use a file trick so the on-disk view does not match the running code.

B1. Process hollowing (RunPE)

Key APIs

CreateProcess(CREATE_SUSPENDED) -> NtUnmapViewOfSection -> VirtualAllocEx -> WriteProcessMemory -> SetThreadContext -> ResumeThread

Description

Start a trusted program suspended, remove its original image, write a malicious image in its place, point the entry to the new code, and resume. The process still shows the trusted name, path, and command line.

Detection

Mismatch between the file on disk and the code in memory, and a process whose main image region does not match its backing file.

B2. Module stomping

Key APIs

(target loads a signed DLL) -> WriteProcessMemory over the DLL's code section

Description

Get a legitimate signed DLL loaded, then overwrite its code in memory with your own. The malicious code runs from inside what looks like a trusted module.

Detection

Compare a loaded module's in-memory code against the file on disk. A signed module whose memory does not match the file is a strong signal.

B3. Process doppelganging

Key APIs

CreateTransaction -> CreateFileTransacted -> WriteFile -> NtCreateSection -> RollbackTransaction -> NtCreateProcessEx

Description

Use an NTFS transaction to write a malicious file, create a memory section from it, then roll the transaction back so the malicious file never commits to disk. Create the process from the crafted section. On-disk scanners see nothing wrong.

Detection

Transacted file activity around process creation, and a process backed by a section with no clean on-disk file.

B4. Process ghosting

Key APIs

CreateFile -> set delete-pending -> NtCreateSection -> close file (deletes it) -> NtCreateProcessEx

Description

Mark the backing file for deletion before creating the process from it. By the time a tool tries to read the file, it is gone, so the running code cannot be checked against a file.

Detection

A process whose backing file is missing or pending deletion at creation time.

B5. Process herpaderping

Key APIs

CreateFile -> write payload -> NtCreateSection -> overwrite the file with benign content -> NtCreateProcessEx

Description

Create the process image from a file, then change the file's contents before the process runs. The file on disk no longer matches the code in memory, which fools tools that scan the file after the fact.

Detection

Compare the running image to the current file contents, and watch for a file being rewritten right after a section is created from it.