Skip to content
Obfuscationintermediate

Dynamic Import Resolution

Instead of a normal import table the program resolves APIs at runtime with LoadLibrary and GetProcAddress over encrypted strings, leaving the static IAT nearly empty and the analyst blind.

Dynamic import resolution hides which APIs a program uses by refusing to declare them in the Import Address Table (IAT). At runtime the code calls LoadLibraryA to get a module handle and GetProcAddress to look up each function by name, using strings that are decrypted or rebuilt on the stack. The static IAT then lists only a couple of loader functions, so a quick triage reveals almost nothing about the malware's behaviour. This is distinct from API hashing, which resolves functions by a hash of their name rather than the plaintext name.

How it works

The program never references the target API directly. It builds the DLL and function name (often decrypted or assembled byte-by-byte to defeat string search), resolves the address, and calls through it. The IAT contains only LoadLibraryA and GetProcAddress.

c
// static IAT shows nothing useful; everything is resolved at runtime
char dll[]  = decrypt("kernel32.dll");
char name[] = decrypt("VirtualAlloc");        // also built on the stack

HMODULE h   = LoadLibraryA(dll);
FARPROC fn  = GetProcAddress(h, name);        // <-- real API recovered here
void *mem   = ((PFN_VirtualAlloc)fn)(0, len, MEM_COMMIT, PAGE_RWX);

Detection & bypass

  • Static — In IDA/Ghidra the imports view is nearly empty except for LoadLibraryA/GetProcAddress. Calls go through register-held pointers (call rax) rather than named thunks, and you see decryption stubs or stack string construction feeding the loader calls. Cross-references from GetProcAddress map the resolution sites.
  • Dynamic — Set conditional logging breakpoints on LoadLibraryA and GetProcAddress, log the requested name (argument) and the returned address (rax/eax), and you immediately get the full list of resolved APIs and where each pointer lives. Frida's Interceptor or API Monitor capture the same mapping without scripting breakpoints.
  • Patch / simplify — Annotate each resolved pointer with the real API name in the disassembler, then dump the process and rebuild a proper IAT so the listing becomes readable and re-runnable.
  • Tools — x64dbg conditional logging breakpoints, Scylla or ImpRec for IAT reconstruction on a dump, Frida Interceptor for live hooking, and API Monitor.
Votes

Comments(0)