{"id":112261,"date":"2026-04-23T07:00:00","date_gmt":"2026-04-23T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=112261"},"modified":"2026-04-23T09:20:44","modified_gmt":"2026-04-23T16:20:44","slug":"20260423-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20260423-00\/?p=112261","title":{"rendered":"Another crash caused by uninstaller code injection into Explorer"},"content":{"rendered":"<p>Some time ago, I noted that <a title=\"Any sufficiently advanced uninstaller is indistinguishable from malware\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230911-00\/?p=108749\"> any sufficiently advanced uninstaller is indistinguishable from malware<\/a>.\u00b9<\/p>\n<p>During one of our regular debugging chats, a colleague of mine mentioned that he was looking at a mysterious spike in Explorer crashes. He showed me one of the dumps, and as soon as I saw the register dump, I said, &#8220;Oh, I bet it&#8217;s a buggy uninstaller.&#8221;<\/p>\n<p>The tell-tale sign: It&#8217;s a crash in 32-bit Explorer on a 64-bit system.<\/p>\n<p>The 32-bit version of Explorer exists for backward compatibility with 32-bit programs. This is not the copy of Explorer that is handling your taskbar or desktop or File Explorer windows. So if the 32-bit Explorer is running on a 64-bit system, it&#8217;s because some other program is using it to do some dirty work.<\/p>\n<p>But out of curiosity, I went to look at why this particular version of the buggy uninstaller was crashing.<\/p>\n<p>This particular uninstaller&#8217;s injected code had a loop where it tried to do some file operations, and if they failed, it paused for a little bit and then tried again. However, the author of the code failed to specify the correct calling convention on the functions, so instead of calling them with the <code>__stdcall<\/code> calling convention, it called them with the <code>__cdecl<\/code> calling convention. In the <code>__stdcall<\/code> calling convention, the callee pops the parameters from the stack, but in the <code>__cdecl<\/code> calling convention, the caller pops them.<\/p>\n<p>This calling convention mismatch means that each time the code calls a Windows function, the code pushes parameters onto the stack, the Windows function pops them, and then the calling code pops them <i>again<\/i>. Therefore, each time through the loop, the code eats away at its own stack.<\/p>\n<p>Apparently, this loop iterated a lot of times, because it had eaten up its entire stack, and the stack pointer had incremented all the way into its injected code. Each time through the loop, a little bit more of the injected code was being encroached by the stack, until the stack pointer found itself <i>inside the code being executed<\/i>.<\/p>\n<p>The code then crashed on an invalid instruction because the code no longer existed. It had been overwritten by stack data.<\/p>\n<p>This <a title=\"'Live Fast, Die Young, Leave a Good-Looking Corpse': Coined by a Chicago Writer\" href=\"https:\/\/www.chicagomag.com\/city-life\/october-2012\/live-fast-die-young-leave-a-good-looking-corpse-coined-by-a-chicago-writer\/\"> left an ugly corpse behind<\/a>, and so many of them that the Windows team thought that it was caused by a bug in Windows itself.<\/p>\n<p>\u00b9 The title is a reference to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Clarke%27s_three_laws\"> Clarke&#8217;s Third Law<\/a>: Any sufficiently advanced technology is indistinguishable from magic.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Inadvertently destroying a staircase while standing on it.<\/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-112261","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Inadvertently destroying a staircase while standing on it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112261","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=112261"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112261\/revisions"}],"predecessor-version":[{"id":112262,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/112261\/revisions\/112262"}],"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=112261"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=112261"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=112261"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}