The File Was Never Executed — But Its DLL Was Loaded
The suspicious file never appeared in the process timeline.
No process creation event.
No command line showing the file being launched.
No obvious execution record under its own name.
It would have been easy to conclude that the file had never run.
But Agent Foskett asked a different question.
Was the file an executable — or was it code that another process loaded?
The answer was sitting in DeviceImageLoadEvents.
The DLL had been loaded inside a legitimate process.

No Process. Still Loaded.
A DLL does not need to appear as its own process to execute code. The investigation had to identify which process loaded the module, where it came from and what happened next.
The process search came back empty
Agent Foskett searched the process telemetry for the filename. Nothing showed the DLL launching as its own process.
That result was useful — but it did not answer whether the DLL's code had been loaded into another process.
A DLL and an executable process are not the same thing.
Process creation was the wrong telemetry
DeviceProcessEvents is excellent for investigating process creation. But a dynamically loaded library can become part of an existing process without creating a new process named after the DLL.For that question, Agent Foskett pivoted to
DeviceImageLoadEvents in Microsoft Defender XDR.The absence of a process event did not prove the absence of execution.
Find the DLL in DeviceImageLoadEvents
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let SuspiciousDll = "version.dll";
DeviceImageLoadEvents
| where Timestamp > ago(30d)
| where FileName =~ SuspiciousDll
| project Timestamp,
DeviceName,
FileName,
FolderPath,
SHA1,
InitiatingProcessFileName,
InitiatingProcessFolderPath,
InitiatingProcessCommandLine
| order by Timestamp ascThere was the execution path
Instead, the image-load event identified the process into which the module had been loaded.
That changed the investigation completely.
Agent Foskett now had a timestamp, DLL path, hash and loading-process context.
The file was absent from the process list because the process list was never where its execution would appear.
The legitimate process did not automatically make the DLL legitimate
That mattered, but it was not a verdict.
Legitimate processes routinely load legitimate libraries. They can also load unexpected libraries because of application behaviour, search-order conditions, plug-in architectures, malicious tampering or other causes.
Agent Foskett therefore investigated the relationship between the process and the DLL rather than judging either object in isolation.
A trusted process can still load an untrusted module.
Where was the DLL loaded from?
Agent Foskett grouped the image-load events by path and loading process.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
let SuspiciousDll = "version.dll";
DeviceImageLoadEvents
| where Timestamp > ago(30d)
| where FileName =~ SuspiciousDll
| summarize Loads=count(),
FirstSeen=min(Timestamp),
LastSeen=max(Timestamp),
Devices=dcount(DeviceId)
by FolderPath,
InitiatingProcessFileName,
InitiatingProcessFolderPath,
SHA1
| order by Loads descSame filename did not mean same file
Two files can have the same filename while containing completely different code. Agent Foskett therefore preserved the hash and path rather than hunting on the filename alone.
That allowed him to distinguish the suspicious module from legitimate files with the same name elsewhere in the environment.
Filename is a clue. Hash and path provide stronger identity.
Pivot back to the loading process
DeviceProcessEvents to reconstruct how that process had started.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
let Device = "FINANCE-LT-07";
let Loader = "legitimate-app.exe";
DeviceProcessEvents
| where Timestamp > ago(24h)
| where DeviceName =~ Device
| where FileName =~ Loader
| project Timestamp,
FileName,
FolderPath,
ProcessCommandLine,
SHA1,
AccountName,
InitiatingProcessFileName,
InitiatingProcessCommandLine
| order by Timestamp ascNow the timeline had two layers
The image-load event explained when that application loaded the suspicious DLL.
Those two event types answered different questions and became much more useful when correlated chronologically.
Process creation told Agent Foskett how the host process began. Image-load telemetry showed what code became part of it.
What happened after the DLL was loaded?
Did the loading process make an unusual network connection? Did it create or modify files? Did it launch another process? Did its behaviour change immediately after the module-load event?
Agent Foskett used the DLL load timestamp as an anchor for the surrounding endpoint timeline rather than assuming that the load itself proved malicious behaviour.
Correlate nearby network activity
DeviceNetworkEvents could provide additional context.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
let Device = "FINANCE-LT-07";
let Loader = "legitimate-app.exe";
let LoadTime = datetime(2026-09-30 09:14:00);
DeviceNetworkEvents
| where Timestamp between
(LoadTime .. LoadTime + 10m)
| where DeviceName =~ Device
| where InitiatingProcessFileName =~ Loader
| project Timestamp,
RemoteUrl,
RemoteIP,
RemotePort,
InitiatingProcessCommandLine
| order by Timestamp ascSequence matters — but correlation is not magic
But timing alone does not prove that the loaded DLL caused the network connection.
Agent Foskett treated the sequence as a reason to investigate further and combined it with file reputation, process behaviour, prevalence and other endpoint evidence.
Build the timeline. Do not turn sequence into causation without evidence.
How widespread was the DLL?
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
let DllSHA1 = "0123456789abcdef0123456789abcdef01234567";
DeviceImageLoadEvents
| where Timestamp > ago(30d)
| where SHA1 =~ DllSHA1
| summarize Loads=count(),
FirstSeen=min(Timestamp),
LastSeen=max(Timestamp)
by DeviceName,
FolderPath,
InitiatingProcessFileName
| order by LastSeen descRare still did not mean malicious
But software versions, locally developed applications and one-off packages can also produce low-prevalence modules.
Agent Foskett used prevalence to scope the investigation — not to manufacture a verdict.
Rarity changes priority. Evidence determines conclusion.
Build the DLL-loading timeline
What Agent Foskett checked
What the evidence can and cannot prove
DeviceImageLoadEvents can provide evidence that an image such as a DLL was loaded by a process where the relevant telemetry is available.That is not the same as proving every internal function the module executed or attributing every later action by the process to that DLL.
Likewise, a legitimate process loading an unexpected DLL is not automatically proof of compromise. Analysts still need path, hash, prevalence, reputation, process lineage, application context and surrounding behaviour.
Prove the load. Reconstruct the context. Do not claim more than the telemetry establishes.
The lesson
That did not mean it had never participated in execution.
Agent Foskett moved from
DeviceProcessEvents to DeviceImageLoadEvents and found the missing evidence: the DLL had been loaded into another process.He identified the loading process, checked the DLL path and hash, reconstructed the process lineage, scoped the module across the environment and correlated the activity that followed.
A file does not need its own process to become part of execution.
Related investigations
Final thought
It cannot answer every question about code execution.
When the suspicious object is a DLL, follow the image-load telemetry. Identify the process that loaded it. Preserve the path and hash. Then correlate the surrounding endpoint behaviour.
The file was never executed as its own process.
Agent Foskett found where its code was loaded instead.
Follow the evidence. Build the timeline.
The Logs Already Knew! 🔎

