Detect Dynamic API Resolution in Google Chronicle
Adversaries may obfuscate then dynamically resolve API functions called by their malware in order to conceal malicious functionalities and impair defensive analysis. API functions called by malware leave static artifacts such as strings in payload files and in the Import Address Table (IAT). To avoid static analysis, adversaries use dynamic API resolution: hashes of function names are stored in malware in lieu of literal strings, and malware uses GetProcAddress() and LoadLibrary() to manually reproduce the linking process. Threat actors including Mustang Panda, Lazarus Group, Latrodectus, Bazar, Brute Ratel C4, TONESHELL, PlugX, Raccoon Stealer, AvosLocker, and CHIMNEYSWEEP use this technique.
MITRE ATT&CK
- Tactic
- Defense Evasion
- Technique
- T1027 Obfuscated Files or Information
- Sub-technique
- T1027.007 Dynamic API Resolution
- Canonical reference
- https://attack.mitre.org/techniques/T1027/007/
YARA-L Detection Query
rule dynamic_api_resolution_core_dll_load {
meta:
author = "Argus Detection Engineering"
description = "Detects T1027.007 - Dynamic API Resolution via core Windows DLL loads from non-standard process paths"
severity = "HIGH"
mitre_attack_tactic = "Defense Evasion"
mitre_attack_technique = "T1027.007"
reference = "https://attack.mitre.org/techniques/T1027/007/"
created = "2026-04-13"
false_positives = "Portable apps, dev tools outside Program Files, custom enterprise software paths"
events:
$e.metadata.event_type = "PROCESS_MODULE_LOAD"
$e.target.file.full_path = /(?i)(kernel32\.dll|kernelbase\.dll|ntdll\.dll)$/
not $e.principal.process.file.full_path = /(?i)^[Cc]:\\Windows\\/
not $e.principal.process.file.full_path = /(?i)^[Cc]:\\Program Files/
not $e.principal.process.file.full_path = /(?i)^[Cc]:\\Program Files \(x86\)/
not $e.principal.process.file.full_path = ""
$hostname = $e.principal.hostname
$process_path = $e.principal.process.file.full_path
$dll_name = $e.target.file.full_path
$process_sha256 = $e.principal.process.file.sha256
match:
$hostname, $process_path over 5m
outcome:
$risk_score = max(65)
$distinct_core_dlls = count_distinct($dll_name)
$loaded_dlls = array_distinct($dll_name)
$observed_hashes = array_distinct($process_sha256)
condition:
#e >= 1 and $distinct_core_dlls >= 1
} Chronicle YARA-L 2.0 rule that fires on PROCESS_MODULE_LOAD events where core Windows DLLs (kernel32.dll, kernelbase.dll, ntdll.dll) are loaded by a process whose executable path falls outside standard Windows installation directories. Events are grouped by hostname and process path within a 5-minute window, and the outcome captures distinct DLL names and observed process hashes for analyst triage. This pattern is consistent with malware families such as Lazarus Group, Mustang Panda, Latrodectus, and Brute Ratel C4 that implement hash-based API obfuscation.
Data Sources
Required Tables
False Positives & Tuning
- Third-party security products (AV engines, EDR sensors) deployed to custom installation paths that perform DLL instrumentation and interception at the OS level as part of their normal protection mechanism
- Developer toolchains including compilers, linkers, build systems, and debuggers that run from build output directories and dynamically load core system libraries during linking or symbol resolution
- Enterprise LOB applications deployed via group policy or deployment tools to organization-specific directory structures outside Program Files that legitimately load kernel32.dll and ntdll.dll at process initialization
Other platforms for T1027.007
Testing Methodology
Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1Demonstrate GetProcAddress Dynamic API Resolution in PowerShell
Expected signal: Sysmon Event ID 1: PowerShell process creation with Add-Type and DllImport. PowerShell ScriptBlock Log Event ID 4104: the P/Invoke declarations and GetProcAddress call. Sysmon Event ID 7: user32.dll loaded by powershell.exe.
- Test 2API Hash Resolution Simulation
Expected signal: PowerShell ScriptBlock Log Event ID 4104: the hash function implementation and the list of API names being hashed. The output shows API-to-hash mappings as adversarial malware would store them.
- Test 3Inspect Binary IAT for Dynamic Resolution Indicators
Expected signal: Sysmon Event ID 1: dumpbin.exe execution with /imports argument on calc.exe. The findstr filter shows LoadLibrary and GetProcAddress imports if present.
- Test 4Create Minimal-Import Executable for Testing
Expected signal: Sysmon Event ID 1: csc.exe compilation (T1027.004 indicator). Sysmon Event ID 1: dynapi.exe execution from Temp. Sysmon Event ID 7: kernel32.dll and user32.dll loaded by dynapi.exe. The dynapi.exe IAT will contain only LoadLibrary and GetProcAddress.
References (5)
- https://attack.mitre.org/techniques/T1027/007/
- https://www.huntress.com/blog/hackers-no-hashing-randomizing-api-hashes-to-evade-cobalt-strike-shellcode-detection
- https://www.blackhat.com/docs/us-15/materials/us-15-Choi-API-Deobfuscator-Resolving-Obfuscated-API-Functions-In-Modern-Packers.pdf
- https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware
- https://dr4k0nia.github.io/dotnet/coding/2022/08/10/HInvoke-and-avoiding-PInvoke.html
Unlock Pro Content
Get the full detection package for T1027.007 including response playbook, investigation guide, and atomic red team tests.