What is a Suspended Process?
A suspended process is a process that starts without immediately executing its main thread. Now, what is the main thread? That’s a great question! You can think of the main thread like the main()
function in C/C++. When a process is created in a suspended state, it means the process has started but is halted, waiting for further instructions such as calling ResumeThread()
to continue execution.
In simple terms, we are starting a process and telling it to pause before executing its main thread.
Why Do We Need a Suspended Process?
1. Process Injection & Code Execution
Malware developers use suspended processes to inject malicious code into virtual memory before the main process executes. This allows attackers to execute payloads stealthily.
2. Debugging & Hooking
Suspended processes are also used by Antivirus (AV) and Endpoint Detection & Response (EDR) solutions. Instead of executing a suspicious EXE or DLL immediately, AV/EDR creates the process in a suspended state to analyze and debug binaries before execution.
Now, let’s create a C# program to start a process in a suspended state.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace SuspendedProcessDemo
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
struct STARTUPINFO
{
public int cb;
public IntPtr lpReserved;
public IntPtr lpDesktop;
public IntPtr lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
static void Main()
{
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
string targetProcess = "C:\\Windows\\System32\\notepad.exe";
CreateProcess(
targetProcess,
null,
IntPtr.Zero,
IntPtr.Zero,
false,
0x00000004, // Suspended mode
IntPtr.Zero,
null,
ref si,
out pi);
}
}
}
Understanding the Code Bit by Bit
The code begins with Namespace Declarations:
using System;
using System.Diagnostics; // Provides tools for working with processes
using System.Runtime.InteropServices; // Allows interaction with Windows API
Next, we define two structs: STARTUPINFO
and PROCESS_INFORMATION
. These structures are initially empty and will later store information when we create a process.
Using P/Invoke to Call CreateProcess
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
We use P/Invoke (Platform Invocation Services) to import the CreateProcess
function from from WinAPI (Microsoft Docs) kernel32.dll
, enabling us to create a new process in a suspended state.
The function has 10 parameters, but we are primarily interested in dwCreationFlags
, which determines how the process starts. Setting this to 0x00000004
tells Windows to create the process in a suspended state. Other parameters can be set to null
or IntPtr.Zero
when not needed.
Initializing STARTUPINFO
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
This creates an instance of the STARTUPINFO
struct. cb
stands for count of bytes, and Marshal.SizeOf(si)
calculates the size of the structure in bytes. This is necessary because CreateProcess
expects cb
to be set before the function is called.
Creating the Suspended Process
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
string targetProcess = "C:\\Windows\\System32\\notepad.exe";
CreateProcess(
targetProcess,
null,
IntPtr.Zero,
IntPtr.Zero,
false,
0x00000004, // Suspended mode
IntPtr.Zero,
null,
ref si,
out pi);
We create an instance of the PROCESS_INFORMATION
struct, which will store information about the process, such as:
- Process Handle
- Thread Handle
- Process ID
- Thread ID
We define targetProcess
as Notepad.exe. The dwCreationFlags
is set to 0x00000004
, which halts the main thread, keeping the process suspended.
Verifying the Suspended Process
After executing the program, open Task Manager and check if notepad.exe
appears in the “Suspended” state (as shown in the screenshot). If it does, the code worked as expected.

Next Steps: Process Hollowing
Now that we have successfully created a suspended process, we will explore Process Hollowing in the next post.