Adventures in application compatibility: The case of the PC-relative indirect jump that reads from nowhere

Raymond Chen

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:

.. 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::RefreshPixieDust method crashed at the call to user32!Set­Window­Pixue­Dust:

00000001`4004345c 48ff1555c92700  call    qword ptr [explorer!_imp_SetWindowPixieDust (00000001`402bfdb8)]
00000001`40043463 0f1f440000      nop     dword ptr [rax+rax]

A look at the Set­Window­Pixie­Dust 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.


Discussion is closed. Login to edit/delete existing comments.

  • word merchant 0

    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.

    • Ron ParkerMicrosoft employee 0

      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.

  • Paul Jackson 0

    > 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.

    • Antonio Rodríguez 0

      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. Chances are you’ll find the only feasible way to do that is at the source level – which will exclude 99.9% of your userbase, even if you publish your product’s source code.

      If you want to do something unsupported by the API, you end up having to patch the binaries, and one way of that is detouring. All forms of binary patching are dangerous and often unsupported: at any time and without warning, an internal function can change its entry point address or parameters, or disappear completely. So if you start patching the binary, you are entering the “Here be dragons” zone. You don’t need Microsoft to tell you that. You are supposedly smart enough to know what you are doing and its consequences.

      Unfortunately, when the patch fails, the crash is in Explorer’s process, so to the end user, the blame goes to Microsoft instead of (in this case) the antivirus maker. So I agree with the first comment: Microsoft should do everything in their hand to block binary patches. In fact, it would be a very good measure against malware. But my psychic powers tell me they can’t because of technical and/or compatibility reasons.

      • David Trapp 0

        Plus, it’s Microsoft who created the Detours library in the first place:

        • Ron ParkerMicrosoft employee 0

          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 caused this problem, though, because it was able to detect and adjust RIP-relative addressing and a number of other less-obvious pitfalls the details of which I have mercifully forgotten. It probably still didn’t catch every case.

          (Editing to add: one of the details that I’ve now regretfully remembered is that it also handled conditional jumps that exited the chunk of code that was being detoured. Those are also RIP/EIP-relative, of course, but in a messier way.)

          And, of course, it only handled x86 and x86_64. Good luck to whoever’s maintaining it today.

        • Emily Bowman 0

          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.

      • Paul Jackson 0

        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.

        • Antonio Rodríguez 0

          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) the Windows XP Start Menu, they would have to stick with that design; otherwise, the API would likely have been to be broken in major redesigns (such as the ones in in Windows 7, 8, 10 and 11). And then people would yell because the Stat Menu hasn’t changed in 20 years, or because Microsoft knowingly broke a public API.

          In fact, you can see where this leads by looking at other OSes. Linux has that very same problem, with all the “desktop wars”. You can choose between hundreds of distributions which use, at least, a dozen different desktop environments (Gnome, KDE, LXDE…), each one with its own customizations. You can grab the source code and modify it to your heart’s content, or add the hooks needed for what you want to do. But it probably will only work with one distribution, and will stop working if it switches to a different environment, or even when it upgrades to a newer version with a different design.

  • Yuhong Bao 0

    Do you know why they needed to detour?

Feedback usabilla icon