Pages

Tuesday, June 26, 2012

Customizing Blue Screen of Death

It's Turned Blue! Is It OK?

BSOD is a response of the kernel to a non-recoverable exceptional situation. If you see it, something really unpleasant has happened.


Kernel environment sets numerous restrictions to a programmer's freedom of actions: consider IRQL, synchronize access to shared variables, don’t spend much time in an ISR, and verify any data from the "userland"... If any of the rules is broken, you'll get a real reproof filled with template phrases in a standard VGA mode with lousy coloring.

In fact, there is a point in all this. If in case of a non-handled exception or logic corruption in the user mode, an application just shuts down, not even bothering to cover up its tracks (the kernel will politely do the job for it), it won't lose its user mode mates, won't screw up their integrity, let alone the integrity of the whole system. Well, yes, it CAN affect a couple of applications it is bound to via interprocess communication, but no more than that.

In the kernel mode, everything is different. First of all, it's not an apartment that kernel mode mates share, but a room. They are not separated by solid walls that would guard residents against tanked tricks of their roomies. Moreover, bounds between kernel mode modules are thin and fragile. The kernel and its components are like a giant clock with infinite number of components. And that's the whole point: if one screw is damaged, the whole system stops. Sure, there are modules which, if failed, don't affect the operating system. As an option, the faulty module might be isolated – the way it is done in certain operating systems, if you know what I mean. However, according to the logic, the kernel component actively interacts with other components and the OS kernel, thus, a failure in one component can lead to a chain of failures in the others and finally destroy all kernel structures or, even worse, corrupt the user data. Moreover, such concealed bugs are very difficult to fix.

Still, suppose you are a lamer. What will be your probable reaction to the blue screen?
Now suppose you are an administrator. How would you react to BSOD? Before you start doing stuff like reading the error code?

And if you are a kernel developer and you've seen this sophisticated debug echo thousands of times? What comes to your mind when you see it again? Besides interjections?


In any case, we have an invincible obstacle for the system to continue its work on the one hand, and priceless unrecoverable neurons, on the other. What should we do? Hooking KeBugCheck is not an option: we are all quite aware of the consequences. And the new Windows 8 with its sweet DirectX BSOD is still to be expected. Meanwhile...

Like Russinovich Did

I believe, everyone knows the name. Russivich is a fox, but he is a cool fox. Within the heaps of Sysinternals utilities, there is quite a curios one - NotMyFault. It can artificially generate various errors in the kernel, which, of course, will be displayed on the BSOD. Besides, it provides an interesting feature - a possibility to change the color and the font size of the death screen. This utility is so great that they even provide it with the source code! But, as I already mentioned, Russinovich is cool...

It took me a while to figure out what was going on: The ioctlcmd.h header file contains the following code:
#define IOCTL_BSOD_COLOR (ULONG) CTL_CODE(FILE_DEVICE_MYFAULT, 0x10, METHOD_BUFFERED, FILE_ANY_ACCESS)
But this is the only place that has a trace of the code responsible for changing the color of the death screen . Myfault.c contains a book of recipes for all sorts of kernel perversions but the main dish! But! Apparently, the compiled driver does contain the necessary code, since it runs perfectly well. "Okay", I thought.
Let's change our focus for a moment. Before you decide to splice anything in the kernel, take the trouble to visit MSDN because the kernel contains plenty of callback functions in it . This is true for the blue screen, as well: There is a callback function which is called right after the blue screen appears. It's registered by the following function:
BOOLEAN KeRegisterBugCheckReasonCallback(
  __out PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
  __in  PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
  __in  KBUGCHECK_CALLBACK_REASON Reason,
  __in  PUCHAR Component
 );
This callback function specifies the reason for its registration: either it has to add something to the dump, or pinpoint the moment when the dump is already added. It also can run just for the sake of it, if KbCallbackReserved1 is specified as the reason. The KbCallbackReserved1 parameter is private and is called earlier than other callback functions in case of critical errors.

There is another, quite similar callback function registered by the following function:
BOOLEAN KeRegisterBugCheckCallback(
  __out   PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
  __in   PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
  __in_opt PVOID Buffer,
  __in   ULONG Length,
  __in   PUCHAR Component
 );
It informs the registered module about a critical error after the deadliest has already happened and the system can be rebooted.

Back to our topic. When I saw CallbackRoutine as an automatically assigned function name  in the disassembler listing, I got absolutely clueless about other places I could check for the miraculous code. And there it was. ... Wait, what is that? Mov – out, mov – out. I don't know, what about you, guys, but I had a feeling that I had been fooled around. I was expecting a miracle, a fairy tale. Instead, Mark just used VGA ports to change the graphic palette. Nothing else but the graphic palette! For example, it turns the blue color into green, so the background turns green.
mov edx, 3C8h       ; the port used for storing the color index in the DAC
 mov al, 4          ; the blue
 out dx, al
 mov al, 0x00003F00 ; turns green (6 bits per color)
 lea ecx, [edx+1]   ; edx = 0x3C9 – the port used for storing color components
 mov edx, ecx
 out dx, al         ; set the Red component
 mov eax, 0x00003F00
 shr eax, 8
 out dx, al         ; Green
 mov eax, 0x00003F00
 shr eax, 10h
 out dx, al         ; Blue 

Well, it is just as good. But I still wanted something more.

Enjoy the Small Things

As a matter of fact, the animated OS boot screen does give a good idea of what you can get out of the VGA mode. You can even guess that a code for graphics rendering, good and ready, is already contained somewhere in the kernel. I won't keep you waiting: we are looking for the Inbv* function family. Note that some of them are even exported from the kernel.  Using the KiDisplayBlueScreen disassembly, we can find the way to use these functions:
if (InbvIsBootDriverInstalled())
 {
   InbvAcquireDisplayOwnership();         // now we give commands
   InbvResetDisplay();                    // clear the screen                                                                                              reinitialize the pallet
   InbvSolidColorFill(0, 0, 639, 479, 4); // fill it with blue
   InbvSetTextColor(15);                  // text in white
   InbvInstallDisplayStringFilter(0);     // reset the callback function for string display
   InbvEnableDisplayString(TRUE);         // enable the string display
   InbvSetScrollRegion(0, 0, 639, 475);   // crop the scroll region
   …
   InbvDisplayString(«Hello world!»);     // display the strings
   …
 }; 

You can easily use these functions in the code of your driver. But don't forget that, once switched to the VGA mode, you won't be able to switch back so easily.

Yet, the Most Curious Function is InbvBitBlt:
VOID NTAPI InbvBitBlt(IN PUCHAR Buffer, IN ULONG X, IN ULONG Y)
Got it? You're right! It is the function that deals with BMP image rendering (that is, a BMP file with 256 colors without a file header). The only problem is that it's not exported. Luckily, it's just a wrap for a similar VidBitBlt function. It's used only to synchronize renderings, which, as a matter of fact, is out of our concern. VidBitBlt, in its turn, is exported from the bootvid.dll, which, as you can guess from its name, entertains users with boot animation. So, have a good trip, guys! Look for loaded modules (absolutely legally), parse the export table and get the pointer to this magic function. And then the only limits you’ll face are the limits of your imagination.

Later, you can use the results to impress your friends or bet a hot dog on them. The main thing is to remember what makes a human different form a machine.

Be positive!

Author: Artem Shishkin, Positive Research

1 comment: