Many native OS PE files still rely on delayed imports. When APIs imported this way are called for the first time, a so-called delay load helper function is executed first – it loads the actual delayed library, resolves the address of its APIs and finally substitutes the APIs’ addresses (that point to a delay load helper function at first) with the actual API functions’ addresses, then the actual API is called. It’s a really clever mechanism that… is kinda obsolete today. Still, from this moment on, any calls to any of the delayed APIs will be redirected to the already resolved APIs addresses.
As expected, some of the DLLs listed as delayed imports by OS EXEs and DLLs are actually not present on the system. This is an opportunity. I originally wanted to research a bit more before publishing anything, but then sixtyvividtails killed it with this comment:
I love this comment, because it demonstrates not only this individual’s in-depth knowledge of the OS but also a good nose for ‘the research opportunities’…
So, since the cat is out of the bag, let’s quickly assess what that means…
There is a small number of EXEs and DLLs (tested on windows 11 23H2) that reference delayed imports pointing to DLLs that do not exist.
For instance, UPPrinterInstaller.exe includes delay-imported APi set (FindLivePdmPrinterById, SavePdmPrinter, RemovePdmPrinterById) from a non-existing PdmUtilities.dll.
Analyzing the logic of the program, we can see that:
"C:\Windows\System32\UPPrinterInstaller.exe" -i -psi 12345678-89ab-cdef-0123-456789abcdef -sid 1234 -oai 12345678-89ab-cdef-0123-456789abcdef -cri 12345678-89ab-cdef-0123-456789abcdef
Yet it still won’t load that precious delay-imported code, because on your typical desktop or server OS instance a call to RtlGetDeviceFamilyInfoEnum that this program does (after checking all the Registry business I faked above) does not return 16 (DEVICEFAMILYINFOENUM_WINDOWS_CORE), but 3 (DEVICEFAMILYINFOENUM_DESKTOP) or 9 (DEVICEFAMILYINFOENUM_SERVER).
Executable files that delay-load phantom DLLs are at least approachable, because we can run them in the best possible conditions that we can create/optimize by creating necessary files, registry entries, etc.
What about DLLs importing delayed PhantomDLLs?
After looking at a few, I am pessimistic. The delay-loaded code usually requires a lot of conditions to be met before it can be reached via typical code paths exposed by the importing DLLs. As such, these are not very promising avenues. And after looking at it for far too long, I got a bit bored and am officially throwing a towel 🙂