A spike of Explorer crashes occurred with the release of a particular Windows Insider build. The crash looked like this:
00007ffb`25cc0000 ff25b29e0600 jmp qword ptr [00007ffb`25d29eb8] ds:00007ffb`25d29eb8=????????????????
The code did not correspond to any loaded DLL, so this is the result of some sort of code injection. The return address on the stack provided a clue:
00007ffb`25cc0000 explorer!TrayUI::RefreshPixieDust+0xab explorer!TrayUI::WndProc+0x1086 .. window message dispatch functions ..
This particular code path runs when you change themes, which isn’t something you do frequently, but even in the a Windows Insider population, it happens often enough that the crashes show up as significant in Windows Error Reporting. The TrayUI::
method crashed at the call to user32!SetWindowPixueDust
:
00000001`4004345c 48ff1555c92700 call qword ptr [explorer!_imp_SetWindowPixieDust (00000001`402bfdb8)] 00000001`40043463 0f1f440000 nop dword ptr [rax+rax]
A look at the SetWindowPixieDust
function shows that it has been detoured!
// normal: 00007ffb`25217560 ff25b29e0600 jmp qword ptr [user32!_imp_NtUserSetWindowPixieDust (00007ffb`25281418)] // crash dump: 00007ffb`25217560 48b80000cb25fb7f0000 mov rax, 7ffb25cb0000 00007ffb`2521756a ffe0 jmp rax
At this point, I did some analysis of the crash dumps to see if there was something common to all of the crashes. And I found one: In every crash, a popular third-party “shell enhancement” was running.
So now we know who is doing the detouring. They’re probably doing it so that they can “add extra features” to Explorer.
Reminder: Detouring the operating system is not supported. This program is doing unsupported things, but their customers don’t know or care.
Let’s take a close look at the crashing instruction:
00007ffb`25cc0000 ff25b29e0600 jmp qword ptr [00007ffb`25d29eb8] ds:00007ffb`25d29eb8=????????????????
Notice that the code bytes are identical to the original instruction: ff 25 b2 9e 06 00
.
The problem is that the instruction they are trying to replicate uses RIP-relative addressing, and they didn’t take that into account. The disassembler is doing you a favor and converting the RIP-relative address to an absolute address. A more literal disassembly would be
00007ffb`25217560 ff25b29e0600 jmp qword ptr [rip+69eb2h]
With this rewrite, it becomes more obvious that just copying this instruction to another location will alter its behavior, since the relocated instruction will have a different rip.
I added to the email thread one of my colleagues who used to work at the company that wrote the software in question, hoping that they might still have contacts at their old company to help get this fixed. My colleague wrote back, “The sad thing here is I wrote the detour code, or at least the 32-bit version of the detour. It looks like they missed a spot when they added 64-bit support.”
Anyway, the company issued a fix for their detour code, and the crashes eventually stopped.
Do you know why they needed to detour?
> They’re probably doing it so that they can “add extra features” to Explorer.
Is it a bad thing that people want or need extra features? If Microsoft would provide some APIs, maybe there won’t be a need in detours.
Of course, it's not a bad thing to have extra features. In fact, Explorer do have an official API for that, in the form of shell extensions, which register through known COM interfaces. But every extension API has to be limited in some way (what is not supported by the API is, by definition, not supported). Try to write a program that does something complex and provide ways to change its behavior in *every* way....
My point is that, in my opinion, the official APIs don’t cover enough use cases. Of course, covering every use case is not feasible, but Microsoft doesn’t cover even the common cases. Do you have APIs to customize the start menu? The taskbar? The explorer ribbon? Barely. And it’s becoming less customizable with time, both for users and for third party software.
Raymond has covered several times the reasons why that level of customization is not covered by the API. For starters, it would open them to be a war zone between competing applications. Would you like that when you open Google Chrome it removes all icons to Firefox or Edge, or place itself in an unmovable panel at the top of the Start Menu? Furthermore, if they did provide a full API to customize (for example)...
Plus, it’s Microsoft who created the Detours library in the first place: https://github.com/microsoft/Detours
It’s worth noting the difference between Detours™ the Microsoft-published library, and “detouring” the microspeak for the general concept — whether that came from the product name or came before and influenced the product name, I wouldn’t know, but I do know it’s very commonly used (especially in .Net) for what other ecosystems generally call “hotpatching” by any means, not just that one library.
While that's true, a lot of ISVs created their own version, because the licensing for Detours was cost-prohibitive for a lot of smaller companies back in the day. That may have changed, but in a lot of cases the die is already cast.
The last project I did for my previous employer, as recently as five years ago, was to create a general-purpose library for various sorts of function/method hooks, including this kind. It wouldn't have...
Just disallow detouring. Microsoft is big enough and rich enough to get away with ruining a few anti-virus and shell extensions (both examples of where the cure is way worse the the disease).
Be honest: any company that promoted Teams on during a pandemic when we couldn’t avoid it clearly has little executive shame.
I don’t believe that there’s any reasonable way to prevent detouring without also preventing fundamental things like JIT compilation. I’d be happy to be proven wrong, of course, even though in my previous life I have caused well more than my fair share of detours.