Skip to content

Remote Thread Injection

How Malware Hides in a Process

Remote thread injection leaves one process's code running inside another, on a thread the first one created, under the target's name, path, parent and signature. A process runs only its own program and the DLLs it loaded, mapped from files, so a thread that starts in memory no file backs is out of place. It usually means code was put there to borrow a trusted name, its account and its network access. Debuggers, security tools and just-in-time compilers leave some of the same traces. Check where each thread starts first, then the region that holds the start.

What It Is

Before, every thread in the process starts in its own program or in a DLL it loaded, and each of those is mapped from a file on disk. After, the process keeps its name, path, parent and signature, but it holds one more thread, created by another process, that starts in private memory no file backs.

That region is the one thing that changed. It is executable, and it often holds a whole program image, which starts with MZ (4D 5A). Where a DLL was forced in through the Windows loader, the module list also shows a DLL from a folder the program never uses.

What Changes Inside the Process

The process is shown before and after, and the pointer marks what changed.

Each thread is drawn where its start address lands, in a module mapped from a file or in private memory that no file backs.

Before

A clean Windows 11 install

On a clean install, every thread of the print spooler starts in spoolsv.exe or a DLL it loaded. Example values.
  • Loaded Modules

    • C:\Windows\System32\spoolsv.exeTID 2460Start Addressspoolsv.exe+0x1240
    • C:\Windows\System32\ntdll.dllTID 2464Start Addressntdll.dll+0x9A20
  • Private Memory

    • No thread starts here.
See It in the Window

After

ws-042,

The spooler's threads on ws-042 at 10:08 on 12 Oct 2026. The one created at 10:07:30 starts in no file.
  • Loaded Modules

    • C:\Windows\System32\spoolsv.exeTID 3276Start Addressspoolsv.exe+0x4B10
    • C:\Windows\System32\ntdll.dllTID 3304Start Addressntdll.dll+0x2A3B0
  • Private Memory

    • None (no file)TID 9012Start Address0x21C4F3A1A40File at the StartStarts in memory no file backs: a spooler thread starts in spoolsv.exe or a DLL it loaded. Remote Thread Injection
See It in the Window

What It Leaves Behind

Inside the target there is a thread that starts in executable memory no file backs, outside every loaded module, and that memory often holds code or a PE header. Sysmon event 8 records such a thread with an empty StartModule, and Sysmon event 10 can record the open that came first. Afterwards the genuine process often does things its job never needs, such as reaching the internet.

Why It Matters

Injected code runs under a genuine process's name, path, parent and signature, so a listing never shows it. Its traces are a thread one process started in another, or executable memory that no file backs.

Which Evidence Can See It

Each tile says whether that kind of evidence can see it, and what it shows.

  • Memory

    Sees it

    A memory image holds the thread that starts in private memory no file backs, and the executable region it starts in, while the process runs.

  • EDR Telemetry

    Sees it

    Defender XDR records CreateRemoteThreadApiCall in DeviceEvents, with the process that started the thread and the one it runs in.

  • Disk

    Cannot see

    The target's file stays genuine, so a hash or signature check passes it. Only a dropped program that started the thread is on disk to find.

  • Logs

    Partly

    Sysmon event 8 in Microsoft-Windows-Sysmon/Operational records the thread and where it starts, but only on machines running Sysmon.

How to Confirm It

Work through these in order. Each step names the page that shows how.

  1. Read where each thread starts, live with Windows.System.Threads or in a memory image with windows.threads' Win32StartAddress. Where Sysmon runs, event 8 with an empty StartModule records the same start.Threads
  2. Find the region that holds the start with windows.vadinfo, which gives its type, the protection it was created with and its file. Then windows.malware.malfind flags private memory created executable and writable, or executable with a written page. A hit is a lead to dump, and a clean result does not clear it.Memory Regions
  3. Find who holds the process open with the rights to write its memory and start threads. In memory, windows.handles lists that Process handle, and live, Handle lists it with every handle type and the granted access shown. Where Sysmon runs, event 10 records the open.Handles, Pipes and Mutexes
  4. Tie its connections to it, live with Get-NetTCPConnection and in memory with windows.netscan. A connection its job never needs, such as the print spooler reaching the internet, points to code that is not its own.Network Connections
  5. Sweep the whole process. Live, Windows.System.VAD lists executable memory no file backs. In a memory image, windows.malware.ldrmodules shows a private region that starts with an MZ header in no loader list. A hit is a lead to dump, once whoever runs the response agrees.Checking for Injected Code

Investigation Steps With Named Tools

Each question has the tools that answer it on a running machine, and in a memory image, a copy of its memory saved to a file.

  • Which thread starts in memory no file backs, and which process started it?

    On a Running Machine

    In a Memory Image

  • What does the memory at the start hold?

    On a Running Machine

    In a Memory Image

What Defenders See

Each record names its log and what must be switched on to get it.

Record and Where It LandsWhat to ReadHow to Turn It On
8 CreateRemoteThread (opens in a new tab)Microsoft-Windows-Sysmon/OperationalIt is written on any Windows computer running Sysmon.SourceImage started a thread in TargetImage. An empty StartModule means the thread starts outside every loaded module, usually in memory no file backs.Checking for Injected Code shows how to read it.Run Sysmon with CreateRemoteThread events in its configuration.
10 ProcessAccess (opens in a new tab)Microsoft-Windows-Sysmon/OperationalIt is written on any Windows computer running Sysmon.SourceImage opened TargetImage. GrantedAccess with the rights to write memory and create threads, from a source with no reason to, often comes first.Handles, Pipes and Mutexes shows how to read it.Run Sysmon with ProcessAccess events in its configuration, filtered to the accesses that matter.
CreateRemoteThreadApiCall (opens in a new tab)A process created a thread in another process.DeviceEventsDefender XDR, advanced huntingInitiatingProcessFileName started a thread in FileName, the Defender XDR record of the same move. Read rare or unsigned initiators first.The Defender for Endpoint sensor on the device
AsrOfficeProcessInjectionAudited, AsrOfficeProcessInjectionBlocked (opens in a new tab)The attack surface reduction (ASR) rule against Office apps injecting code into other processes fired, in audit or block mode.DeviceEventsDefender XDR, advanced huntingAn Office app was blocked, or audited, as it tried to inject code into another process.The Defender for Endpoint sensor on the device

What It Looks Like

This record is decoded field by field, with what each value means.

8 CreateRemoteThread (opens in a new tab)On ws-042, . The spooler's remote thread on ws-042, as Sysmon event 8 records it where Sysmon runs.
Field, as the Record Writes ItWhat It Tells You
UtcTime2026-10-12 10:07:30.418When the thread was created, one second before the spooler's first connection to 198.51.100.23. Put both on the timeline.
SourceImageC:\Windows\Temp\updsvc64.exeThe process that created the thread, the new service binary in Temp, running as SYSTEM. It has no reason to touch the spooler.
TargetImageC:\Windows\System32\spoolsv.exeThe process the thread runs in, the genuine print spooler. Code there borrows its name, its SYSTEM account and its network access.
StartAddress0x0000021C4F3A1A40Where the new thread begins, in no module, inside the private region at 0x21C4F3A0000. Find that region with windows.vadinfo or windows.malware.malfind.
StartModule-Empty, so the start lies outside every loaded module. It is a lead, not proof, so read the region in memory and judge the source process.
StartFunction-Empty too, so the start is at no known exported function either. Together the two rule out a normal library entry point.
False Positives

Debugging, diagnostic, management and security tools start threads in other processes for good reasons, Microsoft notes, and SigmaHQ's rule leaves out a print vendor service and VMware Tools for spoolsv.exe. Judge the source, since a known, signed tool in its own folder is usual and a binary in Temp is not.

.NET and other just-in-time compilers make executable private memory in their own processes, which memory scans report.

Blind Spots

A remote thread record covers one way in. Memory checks look for the code whichever way it arrived, so pair the two.

A clean windows.malware.malfind result never clears a process, because it reads the protection each region was created with, not the one it has now. Pair it with windows.malware.suspicious_threads and thread records.

Hunt It

The same hunt is written for four tools, so pick the one you use. Defender XDR and Sentinel queries are in KQL, which you paste into Advanced hunting in the Defender portal or into Sentinel's Logs page. Splunk queries are in SPL, for its Search page, and Velociraptor queries are in VQL, which you run as a hunt.

Needs Defender for Endpoint. Microsoft documents this action type only in the portal's schema reference, so confirm it with DeviceEvents | distinct ActionType. Security tools and debuggers start remote threads too, so a hit is a lead to check, not proof of injection.

KQLDefender XDR, Advanced hunting
// Threads one process started in another (CreateRemoteThreadApiCall), initiators outside the system folders firstDeviceEvents| where Timestamp > ago(30d)| where ActionType == "CreateRemoteThreadApiCall" and ProcessId != InitiatingProcessId| extend FromSystemFolder = InitiatingProcessFolderPath startswith @"C:\Windows\System32\"    or InitiatingProcessFolderPath startswith @"C:\Windows\SysWOW64\"    or InitiatingProcessFolderPath startswith @"C:\Program Files"| summarize Threads = count(), Devices = dcount(DeviceId), FirstSeen = min(Timestamp), LastSeen = max(Timestamp)    by InitiatingProcessFileName, InitiatingProcessFolderPath, FromSystemFolder, Target = FileName| order by FromSystemFolder asc, Devices asc, Threads asc

In a Memory Image

Volatility 3 reads a memory image, and each of its plugins below shows part of this sign.

Rules to Compare With

Security vendors publish detection rules anyone can read. These look for the same thing, so compare your own with them.

Show the 5 Public Rules

How to Prevent It

Each control helps prevent it, and its line says what it does here.

Sources

MITRE ATT&CK is a free public catalogue of the techniques attackers use. Each technique has an ID, such as T1055 for Process Injection, so defenders can name the same behaviour the same way. This page covers these techniques.