Adversaries may use regsvr32.dll and rundll32.exe to load malicious DLLs from suspicious locations to execute arbitrary code or escalate privileges. SOC teams should proactively hunt for this behavior in Azure Sentinel to detect potential DLL loading attacks that evade traditional detection mechanisms.
KQL Query
let GenerateDLLloads = materialize (
DeviceImageLoadEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName =~ "regsvr32.exe" or InitiatingProcessFileName =~ "rundll32.exe"
| where FolderPath startswith @"C:\users" or
FolderPath matches regex @".:\\ProgramData.[^\\\s]+.dll" or
FolderPath matches regex @".:\\Windows.[^\\\s]+.dll"
| extend folder = extract(@".*\\", 0, FolderPath)
| project LoadedDllSHA1 = SHA1, LoadedDllName = FileName, DllLoadTimestamp = Timestamp, DeviceId, DeviceName, folder, DllLoadProcessCommandLine = InitiatingProcessCommandLine, DllLoadProcessCreationTime = InitiatingProcessCreationTime, DllLoadProcessFileName = InitiatingProcessFileName, DllLoadProcessProcessId = InitiatingProcessId, DllLoadProcessSHA1 = InitiatingProcessSHA1, DllLoadProcessParentCreationTime = InitiatingProcessParentCreationTime, DllLoadProcessParentFileName = InitiatingProcessParentFileName, DllLoadProcessParentId=InitiatingProcessParentId
);
GenerateDLLloads
| summarize count() by LoadedDllSHA1
| where count_ < 5
| join kind=inner GenerateDLLloads on LoadedDllSHA1
| join (
DeviceFileEvents
| where Timestamp > ago(7d)
| where ActionType == 'FileCreated' or ActionType == 'FileRenamed'
| extend folder = extract(@".*\\", 0, FolderPath)
| project LoadedDllSHA1 = SHA1, LoadedDllName = FileName, folder, DllCreationTimestamp = Timestamp, DeviceId, DeviceName, DllCreationProcessCommandLine = InitiatingProcessCommandLine, DllCreationProcessCreationTime = InitiatingProcessCreationTime, DllCreationProcessFileName = InitiatingProcessFileName, DllCreationProcessId = InitiatingProcessId, DllCreationProcessSHA1 = InitiatingProcessSHA1, DllCreationProcessParentCreationTime = InitiatingProcessParentCreationTime, DllCreationProcessParentFileName = InitiatingProcessParentFileName, DllCreationProcessParentId = InitiatingProcessParentId
) on LoadedDllName, LoadedDllSHA1, folder, DeviceName
| project LoadedDllSHA1, LoadedDllName, DllLoadTimestamp, DllCreationTimestamp, DllLoadProcessCommandLine, DllLoadProcessFileName, DllLoadProcessParentFileName, DllCreationProcessCommandLine, DllCreationProcessFileName, DllCreationProcessParentFileName, DeviceName, DllLoadProcessSHA1, DllCreationProcessSHA1, folder, DllLoadProcessCreationTime, DllLoadProcessProcessId, DllLoadProcessParentCreationTime, DllLoadProcessParentId, DllCreationProcessCreationTime, DllCreationProcessId, DllCreationProcessParentCreationTime, DllCreationProcessParentId, DeviceId
id: 69eb9fb7-fe0d-4c34-8c81-3a828fc12abd
name: regsvr32-rundll32-abnormal-image-loads
description: |
This query is using the locations where malicious DLL images are often loaded from by regsvr32.dll and rundll32.exe.
Blog:
https://threathunt.blog/dll-image-loads-from-suspicious-locations-by-regsvr32-exe-rundll32-exe/
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceImageLoadEvents
- DeviceFileEvents
tactics:
- Defense evasion
relevantTechniques:
- T1218.010
- T1218.011
query: |
let GenerateDLLloads = materialize (
DeviceImageLoadEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName =~ "regsvr32.exe" or InitiatingProcessFileName =~ "rundll32.exe"
| where FolderPath startswith @"C:\users" or
FolderPath matches regex @".:\\ProgramData.[^\\\s]+.dll" or
FolderPath matches regex @".:\\Windows.[^\\\s]+.dll"
| extend folder = extract(@".*\\", 0, FolderPath)
| project LoadedDllSHA1 = SHA1, LoadedDllName = FileName, DllLoadTimestamp = Timestamp, DeviceId, DeviceName, folder, DllLoadProcessCommandLine = InitiatingProcessCommandLine, DllLoadProcessCreationTime = InitiatingProcessCreationTime, DllLoadProcessFileName = InitiatingProcessFileName, DllLoadProcessProcessId = InitiatingProcessId, DllLoadProcessSHA1 = InitiatingProcessSHA1, DllLoadProcessParentCreationTime = InitiatingProcessParentCreationTime, DllLoadProcessParentFileName = InitiatingProcessParentFileName, DllLoadProcessParentId=InitiatingProcessParentId
);
GenerateDLLloads
| summarize count() by LoadedDllSHA1
| where count_ < 5
| join kind=inner GenerateDLLloads on LoadedDllSHA1
| join (
DeviceFileEvents
| where Timestamp > ago(7d)
| where ActionType == 'FileCreated' or ActionType == 'FileRenamed'
| extend folder = extract(@".*\\", 0, FolderPath)
| project LoadedDllSHA1 = SHA1, LoadedDllName = FileName, folder, DllCreationTimestamp = Timestamp, DeviceId, DeviceName, DllCreationProcessCommandLine = InitiatingProcessCommandLine, DllCreationProcessCreationTime = InitiatingProcessCreationTime, DllCreationProcessFileName = InitiatingProcessFileName, DllCreationProcessId = InitiatingProcessId, DllCreationProcessSHA1 = InitiatingProcessSHA1, DllCreationProcessParentCreationTime = InitiatingProcessParentCreationTime, DllCreationProcessParentFileName = InitiatingProcessParentFileName, DllCreationProcessParentId = InitiatingProcessParentId
) on LoadedDllName, LoadedDllSHA1, folder, DeviceName
| project LoadedDllSHA1, LoadedDllName, DllLoadTimestamp, DllCreationTimestamp, DllLoadProcessCommandLine, DllLoadProcessFileName, DllLoadProcessParentFileName, DllCreationProcessCommandLine, DllCreationProcessFileName, DllCreationProcessParentFileName, DeviceName, DllLoadProcessSHA1, DllCreationProcessSHA1, folder, DllLoadProcessCreationTime, DllLoadProcessProcessId, DllLoadProcessParentCreationTime, DllLoadProcessParentId, DllCreationProcessCreationTime, DllCreationProcessId, DllCreationProcessParentC
| Sentinel Table | Notes |
|---|---|
DeviceFileEvents | Ensure this data connector is enabled |
DeviceImageLoadEvents | Ensure this data connector is enabled |
Scenario: Legitimate DLL registration via regsvr32.exe
Description: A system administrator uses regsvr32.exe to register a legitimate DLL file (e.g., example.dll) located in the system32 directory.
Filter/Exclusion: process.parent_process_name == "regsvr32.exe" && process.image == "C:\\Windows\\System32\\regsvr32.exe"
Scenario: Scheduled Task using rundll32.exe to load a trusted DLL
Description: A scheduled task runs rundll32.exe to load a trusted DLL (e.g., shell32.dll) as part of a routine system maintenance task.
Filter/Exclusion: process.parent_process_name == "schtasks.exe" && process.image == "C:\\Windows\\System32\\rundll32.exe"
Scenario: Admin using rundll32.exe to execute a legitimate COM object
Description: An administrator uses rundll32.exe to execute a COM object (e.g., mscomctl.ocx) for a legacy application compatibility task.
Filter/Exclusion: process.image == "C:\\Windows\\System32\\rundll32.exe" && process.command_line contains "mscomctl.ocx"
Scenario: DLL file loaded by rundll32.exe during system update
Description: A Windows update or system patch uses rundll32.exe to load a DLL from a temporary directory during the update process.
Filter/Exclusion: process.image == "C:\\Windows\\System32\\rundll32.exe" && process.directory contains "Temp" || process.directory contains "WindowsUpdate"
**Scenario