Dynamic winapi resolution is a technique used to modify the structure of the winapi call stack without physically altering the code. WinAPI functions are exported from the kernel32 and ntdll libraries, which Windows loads in memory at startup. Dynamic changes require a re-initialization of Windows API functions; however, when this happens is undefined, so this technique should not be used in production code.
- Dynamic winapi resolution is typically exploited as part of P/Invokes to resolve system calls that need to be made or by malware as an evasion method in order to avoid detection or analysis by antivirus software.
- A common use for dynamic winapi resolution is to perform reflective loading of DLLs that do not have public exports with GetProcAddress(). Another instance is the exploitation of the kernel stack to return control to the attacker. The use of a kernel stack pivot is considered an advanced technique and very limited in scope, as it requires a code buffer that can be used in read-only memory.
- WinAPI functions are exported from the ntdll library, which Windows loads in memory at startup. This library provides APIs to manage system calls and handle I/O requests.
Dynamic Winapi Resolution with GetProcAddress():
For dynamic winapi resolution with GetProcAddress(), a cost function is used to intelligently search through the exports of each exported function by trial and error until the targeted function is found. A callback function is then used to query the RegQueryValueExW function from kernel32.dll, which is called with a parameter that specifies an arbitrary base pointer in the process space where the targeted function should be resolved. If GetProcAddress() finds a matching DLL, it returns a pointer to an address in that DLL.
- The address returned from GetProcAddress() is usually either the beginning of a jump table (if its user-mode exports are also exported) or at a known location within that DLL.
- The target function is called by passing a pointer to the function’s exported address as an argument.
- To perform reflective loading of DLLs that do not have public exports, GetProcAddress() can be used to search through every exported function in the given DLL.
However, this would require a memory copy of the entire DLL, which will be very inefficient when many functions are being searched through. Instead, GetProcAddress() only searches within each individual exported function for one of its exports. When the targeted function is found and its address is passed in as an argument to GetProcAddress(), that address is returned and put into a code buffer.
Countermeasures:
- To protect a Windows application from dynamic winapi resolution,
it is best to restrict access to WinAPI. This can be done by calling the VirtualProtect function before any use of the WinAPI and then restoring it afterward with the VirtualProtect function. - Also, a defense-in-depth approach should be employed, as AV software may not catch these attempts.
- While Windows has a number of protections in place for detecting and blocking these exploits (such as stack cookies), there are many ways of bypassing these protections. For example, automatic process creation does not happen at predictable times and can be exploited using DLL injection (which causes most defenses to fail).
Conclusion:
WinAPI Resolution Techniques are used to resolve the Windows API functions at runtime. WinAPI functions are pushed into the stack by calling LoadLibrary() with a DLL name argument and then pushing the exported function addresses onto the stack by calling GetProcAddress(). This can be done manually, or by using a table look-up which also creates an evasion scenario where no code is executable in memory. WinAPI resolution is performed as part of code injection in a malicious process, as a method of reflective loading or as an evasion technique to avoid detection.