{"id":9442,"date":"2024-09-14T21:31:05","date_gmt":"2024-09-14T21:31:05","guid":{"rendered":"https:\/\/www.hexacorn.com\/blog\/?p=9442"},"modified":"2024-09-14T21:31:05","modified_gmt":"2024-09-14T21:31:05","slug":"the-delayed-import-table-phantomdll-opportunities","status":"publish","type":"post","link":"https:\/\/www.hexacorn.com\/blog\/2024\/09\/14\/the-delayed-import-table-phantomdll-opportunities\/","title":{"rendered":"The delayed import-table phantomDLL opportunities"},"content":{"rendered":"\n<p>Many native OS PE files still rely on delayed imports. When APIs imported this way are called for the first time, a so-called <em>delay load helper<\/em> function is executed first &#8211; it loads the actual delayed library, resolves the address of its APIs and finally substitutes the APIs&#8217; addresses (that point to a delay load helper function at first) with the actual API functions&#8217; addresses, then the actual API is called. It&#8217;s a really clever mechanism that&#8230; 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.<\/p>\n\n\n\n<p>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 <a href=\"https:\/\/x.com\/sixtyvividtails\">sixtyvividtails<\/a> killed it with this <a href=\"https:\/\/x.com\/sixtyvividtails\/status\/1831410281169539202\">comment<\/a>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/sixtyvividtails_delay_load.png\"><img decoding=\"async\" src=\"https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/sixtyvividtails_delay_load.png\" alt=\"\" class=\"wp-image-9452\" width=\"500\" srcset=\"https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/sixtyvividtails_delay_load.png 582w, https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/sixtyvividtails_delay_load-300x78.png 300w, https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/sixtyvividtails_delay_load-500x130.png 500w\" sizes=\"(max-width: 582px) 100vw, 582px\" \/><\/a><\/figure>\n\n\n\n<p>I love this comment, because it demonstrates not only this individual&#8217;s in-depth knowledge of the OS but also a good nose for &#8216;the research opportunities&#8217;&#8230; <\/p>\n\n\n\n<p>So, since the cat is out of the bag, let&#8217;s quickly assess what that means&#8230;<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>For instance, <em>UPPrinterInstaller.exe<\/em> includes delay-imported APi set (<em>FindLivePdmPrinterById<\/em>, <em>SavePdmPrinter<\/em>, <em>RemovePdmPrinterById<\/em>) from a non-existing <em>PdmUtilities.dll<\/em>. <\/p>\n\n\n\n<p>Analyzing the logic of the program, we can see that:<\/p>\n\n\n\n<ul>\n<li>it requires exactly 10 arguments (unlike 8 arguments that are presented as an example on Microsoft pages); in essence, the win11 versions of <em>UPPrinterInstaller.exe<\/em> require additional (on top of 8 already described) argument of <em>usersid\/sid<\/em> f.ex:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-preformatted\">\"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<\/pre>\n\n\n\n<ul>\n<li>it requires some Registry settings to be present for the given printer&#8217;s shared ID (fake here, just for the test):<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><a href=\"https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/UPPrinterInstalls.png\"><img decoding=\"async\" src=\"https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/UPPrinterInstalls.png\" alt=\"\" class=\"wp-image-9453\" width=\"500\" srcset=\"https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/UPPrinterInstalls.png 936w, https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/UPPrinterInstalls-300x50.png 300w, https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/UPPrinterInstalls-768x128.png 768w, https:\/\/www.hexacorn.com\/blog\/wp-content\/uploads\/2024\/09\/UPPrinterInstalls-500x83.png 500w\" sizes=\"(max-width: 936px) 100vw, 936px\" \/><\/a><\/figure>\n\n\n\n<p>Yet it still won&#8217;t load that precious delay-imported code, because on your typical desktop or server OS instance a call to <em>RtlGetDeviceFamilyInfoEnum<\/em> that this program does (after checking all the Registry business I faked above) does not return 16 (<em>DEVICEFAMILYINFOENUM_WINDOWS_CORE<\/em>), but 3 (<em>DEVICEFAMILYINFOENUM_DESKTOP<\/em>) or 9 (<em>DEVICEFAMILYINFOENUM_SERVER<\/em>).<\/p>\n\n\n\n<p>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. <\/p>\n\n\n\n<p>What about DLLs importing delayed PhantomDLLs? <\/p>\n\n\n\n<p>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 \ud83d\ude42<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &#8211; it loads the actual delayed library, resolves the address &hellip; <a href=\"https:\/\/www.hexacorn.com\/blog\/2024\/09\/14\/the-delayed-import-table-phantomdll-opportunities\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[53,80],"tags":[],"_links":{"self":[{"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/posts\/9442"}],"collection":[{"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/comments?post=9442"}],"version-history":[{"count":7,"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/posts\/9442\/revisions"}],"predecessor-version":[{"id":9471,"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/posts\/9442\/revisions\/9471"}],"wp:attachment":[{"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/media?parent=9442"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/categories?post=9442"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hexacorn.com\/blog\/wp-json\/wp\/v2\/tags?post=9442"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}