Agent Foskett Case File • Microsoft Defender XDR • DeviceImageLoadEvents • DeviceProcessEvents • DLL Loading • KQL

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.

Agent Foskett investigating suspicious DLL loading in Microsoft Defender XDR
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.

✓ Find the image-load event
✓ Identify the loading process
✓ Reconstruct the surrounding timeline

The process search came back empty

The investigation began with a suspicious DLL discovered on an endpoint.

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.
Investigation principle: Choose telemetry that matches the behaviour you are trying to prove.

Find the DLL in DeviceImageLoadEvents

Agent Foskett started with the suspicious filename and reviewed every device that had recorded the module being loaded.
find-dll-loads.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 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 asc

There was the execution path

The DLL had not created a process under its own filename.

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

The loading process was a recognised application.

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?

Path context became critical. A library loaded from the application's expected installation directory can tell a very different story from a similarly named DLL loaded from a user-writable or otherwise unexpected location.

Agent Foskett grouped the image-load events by path and loading process.
dll-path-context.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 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 desc

Same filename did not mean same file

DLL names are not unique identities.

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

Once Agent Foskett knew which process loaded the DLL, he returned to DeviceProcessEvents to reconstruct how that process had started.
loading-process-timeline.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 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 asc

Now the timeline had two layers

The process event explained how the legitimate application started.

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?

The next question was behavioural.

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

If the process communicated externally after the DLL was loaded, DeviceNetworkEvents could provide additional context.
network-after-load.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 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 asc

Sequence matters — but correlation is not magic

A network event occurring after a DLL load can be important evidence, especially when the behaviour is unusual for the application.

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?

Agent Foskett searched by hash across the environment to determine whether the exact module was isolated to one endpoint or loaded elsewhere.
dll-hash-prevalence.kql
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 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 desc

Rare still did not mean malicious

An exact DLL hash appearing on only one device can increase investigative interest, particularly when the path and loading process are unusual.

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

The investigation became clear when the different telemetry sources were placed in order.
DLL appearsEstablish the file path, hash and earliest available file evidence.
Host process startsUse DeviceProcessEvents to reconstruct the legitimate process and its parent chain.
DLL is loadedUse DeviceImageLoadEvents to identify the module load and loading process.
Behaviour followsInspect process, file and network activity around the load timestamp.
Hash is scopedDetermine whether the exact DLL appears on other devices.
Evidence is assessedDecide whether the module and resulting behaviour are expected, suspicious or malicious.

What Agent Foskett checked

DLL filenameWhat module name started the investigation?
HashWhich exact file was loaded?
Folder pathWas the module loaded from an expected location?
Loading processWhich executable loaded the DLL?
Process lineageHow did the loading process start?
Post-load activityWhat happened on the endpoint after the module was loaded?

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

The suspicious file never appeared as its own process.

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.
Investigation principle: When process telemetry is empty, ask whether you are looking for a process — or for code loaded inside one.
The file never became a process. Its code still entered one.
Find the module load. Identify the host process. Reconstruct what happened next.
Continue the Investigation

Final thought

A process search can answer whether a file appeared as a process.

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! 🔎
Develop IT.. Protect IT.. GEMXIT.
GEMXIT PTY LTD | GEMXIT UK LTD
Talk to GEMXIT

The File Was Never Executed — But Its DLL Was Loaded

This Agent Foskett investigation examines suspicious DLL loading in Microsoft Defender XDR and shows why an empty process search does not prove that a library was never loaded into a process.

Investigating DLL Loads with DeviceImageLoadEvents

Use DeviceImageLoadEvents to identify the DLL path, hash and initiating process, then pivot into DeviceProcessEvents to reconstruct the host process and its execution chain.

KQL DLL and Module Investigation in Microsoft Defender XDR

Hunt for exact DLL hashes, compare module paths and prevalence, identify the legitimate process that loaded the library and correlate network and endpoint activity around the image-load timestamp.