What the API actually does
CreateRemoteThread starts a thread inside another process. You hand it a
handle to a target and an address to start executing at, and Windows runs that code under the
target's identity, memory space and privileges.
That is the entire appeal for an attacker. Code running inside explorer.exe borrows its
reputation. Network connections appear to come from a signed Microsoft binary, and every detection
rule that whitelists system executables politely stops applying.
The sequence matters more than the call
On its own the import proves close to nothing. Injection needs a specific chain, and the chain is what you should actually be hunting for:
| Step | API | Purpose |
|---|---|---|
| 1 | OpenProcess | Get a handle to the target, with PROCESS_VM_WRITE and PROCESS_CREATE_THREAD |
| 2 | VirtualAllocEx | Allocate memory inside the target process |
| 3 | WriteProcessMemory | Copy the payload into that allocation |
| 4 | CreateRemoteThread | Execute it |
All four in one binary is close to conclusive. Nobody allocates memory in someone else's process by accident, writes code into it by accident, and then starts a thread on it by accident. When the quartet shows up, the open question is no longer whether the binary injects. It is what it injects into, and what the payload does once it lands.
The target is often sitting nearby as a plain string: explorer.exe,
svchost.exe, RegAsm.exe. Pair that with
CreateToolhelp32Snapshot and Process32First and the binary is walking the
process list looking for a host.
Watch for the lower-level variants. NtCreateThreadEx and
RtlCreateUserThread do the same job through ntdll, specifically to dodge
detection rules that only match the documented Win32 name. That makes them a stronger signal, not
a weaker one. Software with an honest reason to inject has no reason to go looking for the
undocumented door.
The legitimate uses, so you do not over-call it
Plenty of real software injects. Discord injects into your games. Steam injects into your games. Your antivirus injects into everything, including, on a bad day, itself. Flagging all of it as malware makes for a long afternoon and a short career.
Expect injection in:
- Debuggers and profilers. Creating a remote thread is how a debugger forces a break in a target process.
- EDR and AV products. Userland hooking works by injecting monitoring DLLs everywhere.
- Accessibility and compatibility shims. Screen readers, input method editors and overlay tools genuinely need to be inside the process.
- Game overlays. Anything that draws on top of someone else's frames is injecting to do it.
What separates them is context rather than API surface: a valid signature from a vendor you can name, an installer that put the binary somewhere sensible, and a payload that is a DLL on disk instead of a buffer decrypted out of a resource section.
How to confirm intent
- Cross-reference backwards. Find the function holding the call and read what prepares its arguments. The address passed as the start routine tells you whether the payload came from a file, a resource, or a decrypted buffer.
- Check what happens just before
WriteProcessMemory. A decryption loop or a resource read there means the payload was deliberately hidden. That is about as close to a confession as static analysis gets. - Look for privilege escalation nearby.
AdjustTokenPrivilegeswithSeDebugPrivilegeis how a process gets handles to targets it has no business touching. - Verify the signature. Legitimate injectors are almost always signed by a vendor you have heard of. Unsigned code with the full quartet is not a grey area.
MITRE mapping
This chain maps to T1055.002, Process Injection: Portable Executable Injection, under both Defense Evasion and Privilege Escalation. If the payload is a DLL loaded from disk instead, you want T1055.001.