1. Introduction: When Windows API Imports Disappear
When analysing a Windows executable, one of the first places a malware researcher may look is the Import Address Table (IAT). It can reveal which Windows functions an application expects to use, providing clues about its functionality.
For example, imports associated with process creation, memory allocation, network communication, or registry modification can help an analyst understand a program's capabilities.
However, some malware samples reveal very few meaningful API imports. The executable may still perform extensive operations after execution, including creating processes, communicating over a network, or modifying system settings.
Why does this happen?
One possible explanation is dynamic API resolution. Instead of relying on the normal import mechanism for every function, the malware locates the required functions while running.
Some implementations go further by using API hashing. Rather than storing readable API names such as VirtualAlloc or CreateProcessW, the malware stores calculated hash values and compares them with hashes derived from available API names.
These techniques complicate static analysis because the executable may conceal the Windows functions it intends to use. For defenders, the challenge is to identify the resolution mechanism and connect it to the program's actual behaviour.
2. Understanding Windows APIs
The Windows API provides functions that applications use to interact with the operating system.
Depending on the application, these functions may support:
Process and thread management.
Virtual memory allocation and protection.
File and registry operations.
Network communication.
Security and authentication operations.
Loading DLLs and accessing exported functions.
For example, CreateProcessW can be used to create a process, while VirtualAlloc can allocate virtual memory. Their presence in a binary may provide useful investigative context, although neither function is inherently malicious.
In conventional executable loading, the Windows loader uses information in the executable's import structures to resolve imported functions.
A program can also locate functions during execution through mechanisms such as LoadLibrary and GetProcAddress.
This second approach is known as dynamic API resolution.
The technique is legitimate in many applications. Software may use it to support optional components, delay loading until a function is needed, or maintain compatibility across different environments.
It becomes suspicious when the resolution behaviour appears alongside other evidence of malicious activity.
3. What Is Dynamic API Resolution?
Dynamic API resolution occurs when a program identifies and obtains access to required functions at runtime rather than relying entirely on statically declared imports.
A common implementation uses Windows loader functionality to load a DLL and retrieve the address of an exported function.
At a high level, the process involves:
Identifying the required DLL.
Loading or locating the relevant module.
Identifying the desired exported function.
Obtaining the function's address.
Calling the function when required.
For example, a program may resolve a Windows function only when it reaches a particular execution path.
This can reduce the number of directly declared imports and make a binary less informative during a quick static inspection.
However, dynamic resolution is not automatically evidence of evasion. Legitimate applications, plugins, security tools, and compatibility layers can use the same mechanisms.
The analyst must determine what is being resolved, how the result is used, and whether the surrounding behaviour is consistent with the program's intended purpose.
4. What Is API Hashing?
API hashing is a technique in which a program identifies an API using a calculated value derived from its name or other identifying information.
Instead of storing a readable function name, the executable may contain a constant representing the function's hash. At runtime, the program calculates hashes for candidate export names and compares them with the stored value.
When a match is found, the program obtains the corresponding function address.
The precise algorithm varies between implementations. Some use simple arithmetic operations, while others incorporate rotations, XOR operations, character transformations, or additional input such as a module name.
This variation makes it difficult to rely on one universal API-hashing signature.
Why malware authors use API hashing
Reduced readable strings: Function names may not appear plainly in the executable.
Less informative imports: The IAT may not reveal the complete set of APIs used during execution.
Analysis friction: Researchers may need to identify the hashing algorithm and map constants back to exported functions.
Compatibility with custom loaders: API hashing can be incorporated into custom loading routines and other in-memory execution mechanisms.
API hashing does not make Windows functions invisible to every analysis method. The executable must still obtain access to the functions it uses, and runtime execution may reveal the relevant addresses, modules, memory activity, and resulting behaviour.
5. API Hashing vs. Dynamic API Resolution
These concepts are related, but they are not identical.
FeatureDynamic API resolutionAPI hashingMain purposeObtain function addresses at runtimeIdentify functions using calculated valuesFunction namesMay remain readableMay be replaced by hash constantsCommon implementationDLL loading and export lookupHash comparison against export namesStatic analysis impactMay reduce visible importsCan make function identification more difficultRuntime analysisMay reveal function lookup and useMay reveal the resolved function or its behaviourLegitimate usesCommon in application developmentPossible in specialised software, but context matters
A program can perform dynamic API resolution without API hashing. For example, it can call GetProcAddress with a readable function name.
Likewise, API hashing can be implemented as part of a custom resolver that enumerates module exports and compares calculated hashes without calling GetProcAddress for each function.
For this reason, analysts should not assume that every dynamically resolved function is hash-based or that every API-hashing implementation uses the same Windows APIs.
6. How to Detect API Hashing During Static Analysis
Static analysis provides the first opportunity to identify signs of concealed API resolution without executing the sample.
Examine the Import Address Table
Start by inspecting the PE import directory.
A binary with few imports is not necessarily malicious. However, a complex executable that appears to perform substantial operating-system activity while importing very few functions deserves closer examination.
Look for imports that may support custom resolution, such as DLL-loading functions, or compare the declared imports with the program's apparent functionality.
Remember that a custom resolver may not use the conventional lookup functions at all.
Inspect readable strings
Extract strings from the executable and look for DLL names, API names, network indicators, file paths, and configuration values.
A lack of readable API names may support the hypothesis that names are concealed or constructed at runtime. It does not prove API hashing, since strings can be encrypted, compressed, encoded, or absent for unrelated reasons.
Review code for hashing behaviour
Disassembly or decompiler output may reveal repeated arithmetic operations applied to character data or values derived from export names.
Potential clues include:
Loops that process strings or export-name data.
Repeated rotations, shifts, XORs, or additions.
Comparisons between calculated values and constants.
Export enumeration followed by a function-address lookup.
Indirect calls through addresses obtained at runtime.
These patterns become more meaningful when they occur together in a routine that searches DLL exports.
Examine PE export structures
A custom resolver may inspect a module's export directory to locate exported function names and addresses.
Analysts can investigate whether the executable references export-related structures or implements logic consistent with enumerating module exports.
Not every custom resolver follows the same structure, so the investigation should focus on the behaviour represented by the code rather than one fixed byte pattern.
7. Detecting Dynamic Resolution During Runtime Analysis
Static analysis may identify a suspicious resolver without establishing which functions the malware actually uses. Dynamic analysis can provide additional evidence.
Run suspicious samples only in a properly isolated malware-analysis environment.
Monitor DLL loading and function lookup
Observe module-loading activity and, where supported, function-resolution behaviour.
A sequence of module lookups followed by indirect function calls may help establish that the program is resolving APIs dynamically.
Some custom resolvers avoid common lookup functions, so the absence of calls to GetProcAddress does not rule out dynamic resolution.
Examine indirect calls
In a debugger, analysts may encounter calls through registers or memory addresses rather than direct calls to named imported functions.
For example, a call through a register can indicate that a function address was obtained earlier and stored for later use.
Indirect calls are normal in many compiled programs. Their investigative significance depends on whether the surrounding code suggests a custom API resolver and whether the resolved functions support suspicious operations.
Correlate with process and memory activity
Monitor the sample for process creation, memory allocation, protection changes, file operations, registry modifications, and network connections.
If a suspicious resolver is followed by unexpected process injection or network activity, these observations can help establish the purpose of the resolved functions.
The goal is to build an evidence-based sequence from function resolution to actual behaviour.
8. Practical Investigation Example
Consider a Windows executable submitted to a malware-analysis environment.
The initial static inspection reveals:
A relatively small set of imported functions.
Few readable Windows API names.
Several constants that appear in repeated comparisons.
Code that appears to inspect module export information.
These observations raise the possibility of API hashing, but they do not confirm malicious intent.
During controlled execution, the analyst observes the program accessing DLL information and making indirect calls. Subsequent telemetry shows an unexpected child process and an outbound connection to an unfamiliar destination.
The investigation should now connect the evidence:
Validate the binary: Record its hash, architecture, metadata, and provenance.
Analyse the suspected resolver: Determine whether it processes exported function names and compares calculated values.
Identify resolved functions: Where possible, map runtime addresses to their modules and exports.
Correlate behaviour: Determine whether the resolved functions correspond to the observed process and network operations.
Assess impact: Investigate any persistence, credential access, data collection, or other activity supported by the evidence.
Record confidence: Separate confirmed observations from unresolved hypotheses.
This example illustrates a useful principle: API hashing is a clue to how the program conceals its functionality, while the resolved functions and subsequent actions help explain what the program actually does.
9. Evidence and Indicators for Analysts
EvidencePotential significanceImportant limitationUnusually small import tableMay indicate custom resolution or a specialised executableSmall programs can legitimately have few importsHash-like constantsMay represent hashed API namesConstants can serve many other purposesRepeated string-processing arithmeticMay indicate a hashing routineHashing is used for legitimate purposes tooExport-directory traversalMay indicate a custom function resolverOther software can inspect exportsIndirect function callsMay indicate runtime-resolved addressesCommon in normal compiled codeDynamic module loadingMay indicate runtime dependency resolutionNot inherently maliciousSuspicious process or network activityMay reveal the purpose of resolved functionsRequires correlation and validation
Analysts should assess the evidence collectively. No single indicator is sufficient to confirm API hashing or malware activity in every case.
10. SOC Detection and Threat Hunting
API hashing is primarily a code-level technique, so it may not produce a dedicated operating-system event or a universal SIEM signature.
SOC teams can improve detection by combining endpoint telemetry, static-analysis findings, memory analysis, and suspicious behaviour.
Endpoint detection
Use EDR alerts and available telemetry to investigate unusual process creation, cross-process access, memory operations, module loading, and indirect execution patterns where the product supports them.
Behavioural correlation
Correlate suspicious resolver characteristics with follow-on actions such as unexpected child processes, unusual outbound connections, credential-access indicators, or attempts to modify security settings.
Threat hunting
Search for related executable hashes, file paths, command lines, parent-child relationships, network indicators, and other evidence identified during sample analysis.
A custom resolver may differ between malware families, so behaviour-based investigation can be more useful than searching for one particular hashing algorithm.
Detection engineering
Where a sample has been analysed in depth, researchers can develop static signatures, YARA rules, or behavioural detections based on validated characteristics.
Rules should be tested against benign software to understand false-positive risks. A rule based only on high entropy, a small import table, or common arithmetic instructions is likely to be insufficiently specific.
11. MITRE ATT&CK Mapping
The following ATT&CK techniques may be relevant when supported by the observed behaviour.
TechniqueIDRelevanceObfuscated Files or InformationT1027Applies when API names or other information are concealed through an applicable obfuscation methodDynamic API ResolutionT1027.007Relevant when the technique is used to dynamically resolve APIs as a sub-technique of obfuscated files or informationDeobfuscate/Decode Files or InformationT1140Relevant when the sample decodes or deobfuscates concealed information during executionProcess InjectionT1055Relevant only when the investigation confirms a process-injection technique
API hashing and dynamic API resolution do not automatically establish process injection, credential theft, or defence evasion. ATT&CK mappings should describe confirmed or well-supported behaviour rather than every capability a sample might possess.
12. Prevention and Defensive Recommendations
Organisations cannot reliably prevent every instance of API hashing through a single configuration setting. A layered defensive approach is more effective.
Deploy EDR: Use endpoint monitoring that can correlate process behaviour, suspicious memory operations, and follow-on activity.
Restrict untrusted execution: Apply application control and least-privilege policies where practical.
Keep systems updated: Patch operating systems and applications to reduce opportunities for initial compromise.
Monitor network activity: Investigate unusual outbound connections associated with suspicious processes.
Use threat intelligence carefully: Enrich confirmed hashes, domains, and IP addresses with reputable intelligence sources.
Improve malware-analysis capability: Maintain isolated environments and documented procedures for static and dynamic analysis.
Preserve evidence: Retain relevant process, memory, and network telemetry for incident investigation.
For incident responders, the most useful outcome is not simply a list of resolved APIs. It is an explanation of how the executable operated, what systems or data it affected, and which controls could detect or prevent similar behaviour.
Conclusion
API hashing and dynamic API resolution make malware analysis more challenging by reducing the visibility of Windows functions in conventional static inspection. Rather than relying entirely on declared imports and readable strings, analysts may need to examine hashing routines, export enumeration, indirect calls, and runtime behaviour.
Neither technique is inherently malicious, and neither guarantees that a sample will evade detection. Their significance depends on how they are implemented and what the program does with the functions it resolves.
By combining PE inspection, disassembly, controlled execution, memory analysis, and endpoint telemetry, researchers can reconstruct concealed functionality and develop more reliable detections.
The key lesson: When API names disappear from a binary, investigate how the program finds its functions and what it does after resolving them.