{"id":98905,"date":"2018-06-04T07:00:00","date_gmt":"2018-06-04T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=98905"},"modified":"2019-03-13T00:41:31","modified_gmt":"2019-03-13T07:41:31","slug":"20180604-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180604-00\/?p=98905","title":{"rendered":"Adventures in application compatibility: Following a detour off a cliff"},"content":{"rendered":"<p>The application compatibility team reported that a program was crashing in its installer. Debugging the installer revealed that it actually triggered <i>three<\/i> exceptions. <\/p>\n<p>The first exception was due to passing an invalid pointer to the <code>lstrlen<\/code> function. However, this didn&#8217;t crash the installer because the <code>lstrlen<\/code> function contains an application compatibility mitigation: If you pass a pointer to invalid memory, it handles the access violation exception by reporting that the string length is zero. <\/p>\n<p>It did this twice, so that is the second exception as well. <\/p>\n<p>The third exception is the one that crashed the installer: A system function wanted to report a runtime issue. It did this by checking if a debugger was present, and if so, it printed a diagnostic message to the debugger so that the developer could see that there was a problem and get a chance to investigate it. <\/p>\n<p>The problem is that the call to <code>Is&shy;Debugger&shy;Present<\/code> was crashing. <\/p>\n<p>And it was crashing because the installer used <a HREF=\"https:\/\/sourceforge.net\/projects\/gplmpgdec\/files\/\">a DLL<\/a> which detours the <code>Is&shy;Debugger&shy;Present<\/code> function when it is loaded, presumably to make it harder to reverse-engineer (though since <a HREF=\"https:\/\/sourceforge.net\/projects\/gplmpgdec\/files\/GPL%20MPEG-1_2%20Decoder\/GplMpgDec012\/\">the source code is freely available<\/a>, it&#8217;s not sure why they are so concerned about it). <\/p>\n<p>But notice that the DLL does not un-detour the function when it is unloaded.&sup1; <\/p>\n<p>Therefore, if you load the DLL and then unload it, you leave the <code>Is&shy;Debugger&shy;Present<\/code> function detoured to a function that no longer exists. And the next person to call the <code>Is&shy;Debugger&shy;Present<\/code> function will crash. <\/p>\n<p>(Also curious is that the DLL is licensed under the GPL, yet the product that uses it makes no mention of the GPL in its license agreement.) <\/p>\n<p>The fix was to remove the debugging message for the particular case that this program&#8217;s installer was tripping over. <\/p>\n<p>&sup1; Not that un-detouring is a perfect solution either, because it runs into the <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20050607-00\/?p=35413\">What if two programs did this?<\/a> problem: Suppose another DLLs also detoured the <code>Is&shy;Debugger&shy;Present<\/code> function. When this DLL unloads, it restores the original function, which also removes the other DLL&#8217;s detour. And then when the other DLL unloads, it restores what it thought was the original function, but which was actually the detour installed by this DLL. As a result, this DLL&#8217;s detour gets <i>reinstalled<\/i>. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>An arrow pointing to nowhere.<\/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-98905","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>An arrow pointing to nowhere.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98905","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=98905"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98905\/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=98905"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=98905"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=98905"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}