Dashboard/Articles/CreateRemoteThread
Windows API

What CreateRemoteThread Tells You About a Binary

It is the textbook process injection primitive and one of the most misread imports in static analysis. Finding it does not make a binary malicious. The three calls that usually sit next to it are a different story.

Updated 9 Aug 2026 ~5 min read API

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:

StepAPIPurpose
1OpenProcessGet a handle to the target, with PROCESS_VM_WRITE and PROCESS_CREATE_THREAD
2VirtualAllocExAllocate memory inside the target process
3WriteProcessMemoryCopy the payload into that allocation
4CreateRemoteThreadExecute 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:

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

  1. 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.
  2. 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.
  3. Look for privilege escalation nearby. AdjustTokenPrivileges with SeDebugPrivilege is how a process gets handles to targets it has no business touching.
  4. 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.

Check a sample for this pattern

FastBin pulls the import table and function cross-references automatically, so the injection quartet and the function using it surface without manual disassembly.

Analyse a sample