Mehmet Ergene
Detecting Vulnerable Drivers (a.k.a. LOLDrivers) the Right Way Using Microsoft Defender for Endpoint

Empty space, drag to resize
A recent poll I conducted revealed a concerning gap in understanding around how to detect vulnerable drivers using Microsoft Defender for Endpoint (MDE) telemetry. So, the results prompted this post; not just to clarify, but to help prevent the propagation of inaccurate detection methods.
Misconceptions in Driver Load Events
In the poll, 20% of respondents selected a table that doesn't even exist in MDE. Even more troubling, 47% chose the ImageLoadEvents table (referring to DeviceImageLoadEvents), which is an actual table but doesn't contain driver load events. Only 33% answered correctly.
Let's set the record straight. The DeviceImageLoadEvents table, as you can see in the documentation, logs DLL load activity, not the driver load activity. Drivers typically use the .sys file extension, not .dll. (If you've ever seen a driver in DLL format, I'd genuinely be interested to know.)
The Correct Data Source: DeviceEvents
To accurately detect driver loads, use the DeviceEvents table where
ActionType == "DriverLoad"
. If you don't know where and how driver load events are logged, you could just do a search in (Table_Name) FileName:".sys"
to identify these events by filtering on .sys file extensions (or simply examining distinct ActionType values for each table).Here's where things also go off-track: AI-generated responses often mislead. For example, some models might suggest queries like:
DeviceFileEvents
| where ActionType == "DriverLoad" // there isn't such event in file events
or:
DeviceImageLoadEvents
| where ActionType == "DriverLoad" // there isn't such event in image load events.
These queries are incorrect. While AI can be useful, always validate your detection logic, especially before sharing it publicly to help others (?!?!!?).
A Reliable KQL Example Using LOLDrivers.io
To detect known vulnerable drivers (LOLDrivers) using MDE telemetry, here's a query that pulls the data from the loldrivers.io dataset and joins it with driver load events both on SHA1 and SHA256 values since there are some missing SHA1 and SHA256 values in LOLDrivers:
let LOLDrivers = externaldata (Category:string, KnownVulnerableSamples:dynamic, Verified:string ) [h@"https://www.loldrivers.io/api/drivers.json"]
with (format=multijson, ingestionMapping='[{"Column":"Category","Properties":{"Path":"$.Category"}},{"Column":"KnownVulnerableSamples","Properties":{"Path":"$.KnownVulnerableSamples"}},{"Column":"Verified","Properties":{"Path":"$.Verified"}}]')
| mv-expand KnownVulnerableSamples
| extend SHA1 = tostring(KnownVulnerableSamples.SHA1), SHA256 = tostring(KnownVulnerableSamples.SHA256)
;
// you can filter the drivers further based on category or verified status
DeviceEvents
| where ActionType == "DriverLoad"
| join kind=inner (LOLDrivers | where isnotempty(SHA256)) on SHA256
| union (
DeviceEvents
| where ActionType == "DriverLoad"
| join kind=inner (LOLDrivers | where isnotempty(SHA1)) on SHA1
)
Final Thoughts
Incorrect guidance, whether from AI tools or well-meaning individuals, can dilute the effectiveness of detection engineering. Always verify your queries using documentation and telemetry validation. Precision matters when you're building detections.
Share this post
Latest from our blog

Copyright © 2025
Featured Links
Subscribe to our Newsletter!
Thank you!
New Challenge Lab
We're excited to launch our first hands-on lab challenge: Threat Hunting and Incident Response Case #001!
This lab simulates a real-world breach with two investigation paths:
This lab simulates a real-world breach with two investigation paths:
1️⃣ Incident Response: Triage an initial alert and unfold the attack.
2️⃣ Threat Hunting: Start with a TTP and hunt for adversary activity.