Uninformed: Informative Information for the Uninformed

Vol 3» 2006.Jan


Introduction

In the caste system of operating systems, the kernel is king. And like most kings, the kernel is capable of defending itself from the lesser citizens, such as user-mode processes, through the castle walls of privilege separation. However, unlike most kings, the kernel is typically unable to defend itself from the same privilege level at which it operates. Without the kernel being able to protect its vital organs at its own privilege level, the entire operating system is left open to modification and subversion if any code is able to run with the same privileges as the kernel itself.

As it stands today, most kernel implementations do not provide a mechanism by which critical portions of the kernel can be validated to ensure that they have not been tampered with. If existing kernels were to attempt to deploy something like this in an after-the-fact manner, it should be expected that a large number of problems would be encountered with regard to compatibility. While most kernels intentionally do not document how internal aspects are designed to function, like how system call dispatching works, it is likely that at least one or more third-party vendor may depend on some of the explicit behaviors of the undocumented implementations.

This has been exactly the case with Microsoft's operating systems. Starting even in the days of Windows 95, and perhaps even prior to that, Microsoft realized that allowing third-party vendors to twiddle or otherwise play with various critical portions of the kernel lead to nothing but headaches and stability problems, even though it provided the highest level of flexibility. While Microsoft took a stronger stance with Windows NT, it has still become the case that third-party vendors use areas of the kernel that are of particular interest to accomplishing certain feats, even though the means used to accomplish them require the use of undocumented structures and functions.

While it's likely that Microsoft realized their fate long ago with regard to losing control over the scope and types of changes they could make to the kernel internally without affecting third-party vendors, their ability to do anything about it has been drastically limited. If Microsoft were to deploy code that happened to prevent major third-party vendors from being able to accomplish their goals without providing an adequate replacement, then Microsoft would be in a world of hurt that would most likely rhyme with antitrust. Even though things have appeared bleak, Microsoft got their chance to reclaim higher levels of flexibility in the kernel with the introduction of the x64 architecture2.1. Since the Windows kernel on the x64 architecture operates in 64-bit mode, it stands as a requirement that all kernel-mode drivers also be compiled to run and operate in native 64-bit mode. There are a number of reasons for this that are outside of the scope of this document, but suffice it to say that attempting to design a thunking layer for device drivers that are intended to have any real considerations for performance should be enough to illustrate that doing so would be a horrible idea.

By requiring that all device drivers be compiled natively as 64-bit binaries, Microsoft effectively leveled the playing field on the new platform and brought it back to a clean slate. This allowed them to not have to worry about potential compatibility conflicts with existing products because of the simple fact that none had been established. As third-party vendors ported their device drivers to 64-bit mode, any unsupported or uncondoned behavior on the part of the driver could be documented as being prohibited on the x64 architecture, thus forcing the third-party to find an alternative approach if possible. This is the dream of PatchGuard[3], Microsoft's anti-patch protection system, and it seems logical that such a goal is a reasonable one, but that's not the point of this document.

Instead, this document will focus on the changes to the x64 kernel that are designed to protect critical portions of the Windows kernel from being modified. This document will describe how the protection mechanisms are implemented and what areas of the kernel are protected. From there, a couple of different approaches that could be used to disable and bypass the protection mechanisms will be explained in detail as well as potential solutions to the bypass techniques. In conclusion, the reasons and motivations will be summarized and other solutions to the more fundamental problem will be discussed.

The real purpose of this document, though, is to illustrate that it is impossible to securely protect regions of code and data through the use of a system that involves monitoring said regions at a privilege level that is equal to the level at which third-party code is capable of running. This fact is something that is well-known, both by Microsoft and by the security population at large, and it should be understood without requiring an explanation. Going toward the future, the operating system world will most likely begin to see a shift toward more granular, hardware-enforced privilege separation by implementing segregated trusted code bases. The questions this will raise with respect to open-source operating systems and DRM issues should slowly begin to increase. Only time will tell.