{"id":36463,"date":"2005-02-14T07:00:00","date_gmt":"2005-02-14T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/02\/14\/loadlibraryexdont_resolve_dll_references-is-fundamentally-flawed\/"},"modified":"2005-02-14T07:00:00","modified_gmt":"2005-02-14T07:00:00","slug":"loadlibraryexdont_resolve_dll_references-is-fundamentally-flawed","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050214-00\/?p=36463","title":{"rendered":"LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES) is fundamentally flawed"},"content":{"rendered":"<p>\nThere is a flag to\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/dllproc\/base\/loadlibraryex.asp\">\nthe <code>LoadLibraryEx<\/code> function<\/a>\ncalled\n<code>DONT_RESOLVE_DLL_REFERENCES<\/code>.\nThe documentation says,\n<\/p>\n<blockquote CLASS=\"m\">\n<p>\nIf this value is used, and the executable module is a DLL,\nthe system does not call\n<a HREF=\"http:\/\/msdn.microsoft.com\/library\/en-us\/dllproc\/base\/dllmain.asp\">\nDllMain<\/a> for process and thread initialization and termination.\nAlso, the system does not load additional executable modules\nthat are referenced by the specified module.\n<\/p>\n<p>\nIf you are planning only to access data or resources in the DLL,\nit is better to use LOAD_LIBRARY_AS_DATAFILE.\n<\/p>\n<\/blockquote>\n<p>\nIn my opinion, the above text that &#8220;suggests&#8221; the\n<code>LOAD_LIBRARY_AS_DATAFILE<\/code> flag is not strong enough.\n<\/p>\n<p>\n<code>DONT_RESOLVE_DLL_REFERENCES<\/code> is a time bomb.\n<\/p>\n<p>\nLook carefully at what the flag does and doesn&#8217;t do.\nThe module is loaded into memory, but its initialization\nfunction is not called and no dependent DLLs are loaded.\n[Typo fixed, 10am.]\nAs a result, you cannot run code from this DLL.\n(More accurately, if you try, it will crash because the DLL\nhasn&#8217;t initialized itself and none of its imports to\nDLLs have been resolved.)\nHowever, unlike the\n<code>LOAD_LIBRARY_AS_DATAFILE<\/code> flag,\nthe loaded DLL <strong>can<\/strong> be found by\n<code>GetModuleHandle<\/code> and can be used by\n<code>GetProcAddress<\/code>.\n<\/p>\n<p>\nClearly, <code>GetProcAddress<\/code> is a bad idea for\nsomething loaded by\n<code>DONT_RESOLVE_DLL_REFERENCES<\/code>, because\nas we already noted, you can&#8217;t run any code from the DLL.\nWhat&#8217;s the point of getting a procedure address from a DLL\nif you can&#8217;t call it, after all?\n<\/p>\n<p>\nThe <code>GetModuleHandle<\/code> part triggers the time bomb.\n<\/p>\n<p>\nIt is common for somebody to call\n<code>GetModuleHandle<\/code> to see\nif a DLL is loaded, and if so, use\n<code>GetProcAddress<\/code> to get a procedure address and\ncall it.  If the DLL had been loaded with\n<code>DONT_RESOLVE_DLL_REFERENCES<\/code>, both the\n<code>GetModuleHandle<\/code> will succeed, but the resulting\nfunction will crash when called.\nThe code doing this has no idea that the DLL was loaded\nwith\n<code>DONT_RESOLVE_DLL_REFERENCES<\/code>; it has no way\nof protecting itself.\n<\/p>\n<p>\n(Note that code that does this is unsafe anyway, because\nthe code that originally loaded the DLL might decide to\ndo a <code>FreeLibrary<\/code> on another thread, causing\nthe code to be ripped out from underneath the first thread.\nThis second problem can be &#8220;fixed&#8221; by using\n<code>GetModuleHandleEx<\/code>, which can be instructed to\nincrement the DLL reference count, but that doesn&#8217;t fix the\nfirst problem.)\n<\/p>\n<p>\nEven if you used <code>LoadLibrary<\/code> to load the DLL\nand passed that handle to <code>GetProcAddress<\/code>,\nyou still crash, because the <code>LoadLibrary<\/code>\nnotices that the DLL is already loaded and merely increments\nthe reference count.\n<\/p>\n<pre>\n#include &lt;windows.h&gt;\ntypedef HINSTANCE (WINAPI *SXA)(HWND, LPCSTR, LPCSTR,\n                                LPCSTR, LPCSTR, int);\nint __cdecl main(int argc, char* argv[])\n{\n if (argc &gt; 1) \/\/ set the time bomb\n  LoadLibraryEx(\"shell32.dll\", NULL, DONT_RESOLVE_DLL_REFERENCES);\n \/\/ victim code runs here\n HINSTANCE h = LoadLibrary(\"shell32.dll\");\n if (h) {\n  SXA f = (SXA)GetProcAddress(h, \"ShellExecuteA\");\n  if (f) {\n   f(NULL, NULL, \"notepad.exe\", NULL, NULL, SW_SHOWNORMAL);\n  }\n  FreeLibrary(h);\n }\n}\n<\/pre>\n<p>\nIf you run this program with no command line arguments, then\neverything works just fine:  Notepad is launched without\nincident.\nHowever, if you pass a command line argument, this sets the time bomb,\nand the call to ShellExecuteA crashes in flames because\nshell32.dll was loaded without having its DLL references resolved.\n<\/p>\n<p>\nIn other words,\n<code>DONT_RESOLVE_DLL_REFERENCES<\/code> is fundamentally flawed\nand should be avoided.\nIt continues to exist solely for backwards compatibility.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There is a flag to the LoadLibraryEx function called DONT_RESOLVE_DLL_REFERENCES. The documentation says, If this value is used, and the executable module is a DLL, the system does not call DllMain for process and thread initialization and termination. Also, the system does not load additional executable modules that are referenced by the specified module. If [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-36463","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>There is a flag to the LoadLibraryEx function called DONT_RESOLVE_DLL_REFERENCES. The documentation says, If this value is used, and the executable module is a DLL, the system does not call DllMain for process and thread initialization and termination. Also, the system does not load additional executable modules that are referenced by the specified module. If [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36463","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=36463"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/36463\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=36463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=36463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=36463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}