Fighting rootkits on Windows 64-bit platforms
Date : October 30, 2012
Introduction
In the fight against malware, antivirus vendors are facing two major challenges:
- First detection: There are more and more worms and Trojans, which are additionally becoming more and more polymorphic. Thus it is nowadays illusive to try to detect them using only signature-based engines. As a consequence, antivirus software are increasingly using heuristic techniques for detections (e.g. study of the malware execution in a sandbox), but all these forms of detection may be flawed.
- Late detection: here we assume that the antivirus software was not able to detect a malware in time, and that it is now installed and hidden on the system.
This is this second scenario which is our concern in the present article. In fact, we are analysing a report recently released by McAfee, which provides a state of the art regarding the detection of rootkits in Windows environments, and particularly the 64-bit platforms.
Some reminders about rootkits
A large number of more or less sophisticated malware include so-called rootkit features. To recap, a rootkit is a software component that has managed to execute itself with the highest level of privileges on an operating system (“kernel-mode” or “ring 0”). Because of this advantageous position, it is then able to prevent its malicious activities from being caught by antivirus software that run in user space (also known as “ring 3”). To do so, the rootkit manipulates kernel memory in real-time (aka patching) and hooks some system functions so that the malware footprint remains invisible for legitimate applications (hiding of files, processes etc.). For example, it is rather easy for a rootkit to completely hide the presence of a process on a system, by hooking the “NtQuerySystemInformation” system call.
Pieces of malware having rootkit functionalities are thus often considered as the most dangerous threats, because they are the most difficult to detect and remove by conventional antivirus solutions.
A bit of history: from 32-bit to 64-bit Windows
Since the origins of Windows 32-bit platforms (Windows 95 was the first 32-bit home public version of the OS), the low-level features of the kernel, including functions that allow low-level access to disks or network devices, were often incomplete and poorly documented. Many third-party software developers were even forced to reverse-engineer the kernel and to use patching/hooking techniques in order to get their programs working properly with certain types of hardware. Then, there were the emergence of rootkits, which used these same tricks in order to cover themselves on an infected system. For all these years, Microsoft was never able to implement protections against rootkits in the Windows kernel, because it was virtually impossible to differentiate non-legitimate hooking/patching methods from the ones used by legitimate software.
With the coming out of 64-bit architectures, Microsoft decided to make a clean break with the past and to implement strong protections in the Windows kernel. There are two major protections brought by the 64-bit kernel:
- Preventive protection: In Windows 64-bit, loading drivers which signature has not properly been verified by the system is not allowed. However, we have seen in recent years that this kind of protection was rather unsatisfactory:
- Certain advanced pieces of malware such as Stuxnet were able to install a rootkit component thanks to a driver signed with legitimate certificates (certificates belonging to Jmicron and Realtek were actually fraudulently used in this way in 2010). More recently in 2012, it has been discovered that the Shamoon malware was using a properly signed commercial driver from the Eldos company to wipe data.
- For practical reasons, this signature check can be legitimately disabled through a setting in the Windows boot loader. Certain bootkits (they are actually rootkits that manage to install on a system by altering the system master boot record) like the one used in the TDL-4 botnet are thus capable of disabling the signature check in the boot loader and then load as a driver within the kernel.
- Reactive protection: The 64-bit kernel includes a module which goal is to prevent illegal alterations (patching) of certain critical memory areas in real-time. This patch protection module is commonly referred as PatchGuard. We are going to focus on this module for the rest of the present article.
A brief presentation of PatchGuard
PatchGuard is a component of the 64-bit Windows kernel which is in charge to check, at random intervals, the integrity of certain key memory areas. If it detects an inconsistency in one of these key areas, it halts the system displaying the famous “blue screen of death” with the special error code 0x109, in such a way to report that the system integrity has been compromised. PatchGuard is in particular able to check the integrity for:
- System modules (NTOS, NDIS, HAL …).
- The System Service Dispatch Table (SSDT): This table allows to easily find in memory the code associated to a system call (patching this table is one of the most common techniques used by rootkits),
- The Global Descriptor Table (GDT): This is the table that allows the conversion of virtual memory addresses (the addresses used by processes) into physical addresses.
- The Interrupt Descriptor Table (IDT): This table allows the handling of hardware and software interrupts.
- The Model-Specific control Registers (MSR): These are registers of Intel processors that facilitate the tracing and debugging of code execution. They also allow enabling/disabling certain specific CPU features.
In order to prevent third-party modules or drivers from attacking it, PatchGuard consists in an extremely complex and sophisticated code:
- It uses obfuscation and randomization techniques at all levels, either during its initialization or its further operations.
- It continuously performs self-integrity checks.
- Various initialization and operation steps use self-decrypted and self-modified code.
- Several instances of the validation routines may be run at the same time and located at random memory addresses.
- The code uses deferred procedure system calls (aka DPC).
- All the initialization and verification steps use multiple misleading redirections in the execution flaw. This even includes triggering exceptions voluntarily.
- PatchGuard is disabled when the kernel is switched to debug mode.
To our knowledge, PatchGuard is the first implementation of a protection against illegal patching in an operating system kernel. In addition, because of the complexity and sophistication of PatchGuard, there are currently only a small number of operational 64-bit rootkits. But for how long?
PatchGuard limitations
The major limitation of PatchGuard is the fact that it runs with the same privilege level (ring 0) as the malicious drivers or rootkits it is supposed to monitor. Consequently, the situation in memory may be compared to a race or a battle in which the winner would be the one which first annihilates the other. In particular, because PatchGuard is not running continuously, it may be deactivated in an interval between two memory checks.
In its report, McAfee recalls several theoretical attacks against PatchGuard that have already been illustrated in the past by various security researchers. Most of these attacks have since then been blocked by Microsoft through their Service Packs for Windows Vista and Windows 7. Here are some examples of such attacks:
- Exception handler functions hooking: The PatchGuard validation routine is often triggered through exceptions generated from the deferred kernel procedure calls (DPC). A rootkit is thus potentially able to set a hook on one of these exception handlers to take control of the execution flaw and prevent the PatchGuard memory checks.
- “KeBugCheckEx” routine (0x109) hooking: This function is in charge of halting the system in case of illegal memory corruptions and displaying the blue screen. Today, with the latest Windows Service Packs, PatchGuard makes its own copy of this function overwriting the execution stack, in order to prevent the hooking.
- Manipulating the debug registers found on Intel x64 processors (DR0 through DR7): These registers allow setting breakpoints that are triggered when specific memory addresses are read/written. A rootkit can define breakpoints on memory addresses it controls so as to modify the execution flaw of the PatchGuard checks, thus preventing the system from detecting illegal kernel patching.
- Patching the kernel timer DPC dispatcher: A rootkit may rather easily detect the location of this dispatcher, modify it, and then decide whether or not a DPC call should be executed. The dispatcher hook will therefore filter the DPC calls that appear to be related to PatchGuard, and go through the other ones that consist in normal kernel operating tasks.
- Etc.
In its report, McAfee finally states that it has developed its own attack against PatchGuard. This attack is more generic, because it essentially consisted in studding the way the PatchGuard code decrypts itself in memory. During its initialization, PatchGuard decrypt the first part of its own code, code which then allows decrypting the remaining instructions. The McAfee Proof-of-Concept code just needs to search the whole kernel memory for occurrences of this code (similar to a traditional antivirus signature match) and to append an encrypted representation of the return instructions. According to McAfee, this allows to effectively disable PatchGuard once for all, on all versions of Windows including Windows 8.
Conclusion: towards a new level of security
McAfee concludes on this rather basic concept: It is impossible to protect a system from an attack that runs at the same privilege level at which its protection code runs. In fact, both codes (in the present case: PatchGuard and a rootkit) have permissions to perform the same operations on the processor and have no restriction regarding their memory access. As a consequence, PatchGuard is only a way to make rootkit attacks more difficult, but remains a vulnerable solution by nature. In other words, a malicious code that has reached “ring 0” can not be countered anymore in an operating system.
The solution proposed by McAfee and its partner, Intel, is to base this protection on the hardware: the CPU in this case. The solution that have been presented, so-called DeepSAFE, uses the virtualization features of the latest Intel x86_64 processors to run a secure layer of code at a new highest privilege level (McAfee call it “VMX root”, but we could call it “ring -1”). The operating system kernel code still runs at its intended level of privileges (ring 0). In this new model, the new secure layer of code configures key areasincluding CPU registers and memory areas for protection. If a kernel component tries to modify these protected key areas, the hardware generate what we could call a special exception which gives back the execution flaw to the DeepSAFE security layer, which decides whether to allow the modification.
To conclude, we are entirely aware of the fact that the McAfee report we studied is first and foremost a good advertisement for their collaboration with Intel and the latest technologies they have developed together. DeepSAFE is certainly not a panacea and security researchers will probably soon find flaws in its implementation. However, we believe the report had the merit of offering a graceful solution to the rootkit challenge.
References
- Bypassing PatchGuard on Windows x64 (Skywing)
- Subverting PatchGuard Version 2 (Skywing)
- PatchGuard Reloaded: A Brief Analysis of PatchGuard Version 3 (Skywing)
- Defeating PatchGuard (McAfee)