A Brief Analysis of Microsoft PatchGuard MSR Protection
By Gal Diskin | October 10, 2013
In the course of implementing the next generation of kernel defenses here in Cyvera I found myself analyzing certain PatchGuard features in order to create defenses that enhance PatchGuard capabilities as well as create defenses that go beyond it. As part of this process I performed a very partial study of PatchGuard (Kernel Patch Protection) MSR defense on a fully patched Windows 7 x64 machine. I’m sharing here today some of the observations and findings as a service to the security community. Some information contained here is conjecture. Since my intention is not to reverse engineer the Windows kernel but to enhance and co-exist with PatchGuard I have not spent the time to perform the additional analysis required to prove or disprove certain conjectures.
Very little official information exists about PatchGuard. The “Windows Internals” (6th edition) has a whole one page (wow!) dedicated to PatchGuard which explains each protected item and what is the related risk. Items protected:
- Ntoskernel.exe, Hal.dll, Ci.dll, Kdcom.dll, Pshed.dll, Clfs.sys, Ndis.sys, Tcpip.sys.
- GDT & IDT
- MSRs – the subject of this article
- KdpStub, KiDebugRoutine, KdpTrap function pointers
- Kernel stacks
- Object types
- Other stuff related to PatchGuard operation
My interest in this specific case was to analyze the protection on certain MSRs. MSRs are “model specific registers” that exist in CPUs. Contrary to the name, some MSRs are actually part of the official x86 or x64 architecture and not “model specific”. The list of architectural MSR is maintained in the appendix of Intel Software Developers Manual – volume 3. The entire SDM can be freely downloaded here.
I’ll diverge from our main topic for a bit I’d to explain the reason for that and share an amusing story that was told to me back when I started working for Intel. The reason for “model specific” (i.e. non-architectural) registers to appear in the architecture is mostly historical. Way back Intel created the MSRs as an internal configuration mechanism for specific CPUs using MSRs. However, various vendors reverse engineered the code and started using some of the MSRs. As a result Intel was forced by customer requirements to maintain support to these MSRs and provide specifications turning those into part of the x86 and later x64 official architecture. Well, that is the end of the anecdote on how reverse engineering changed the architecture of processors as we know it today.
Back to our main subject, the kernel protects several MSRs. One of the most obvious ones is the IA32_LSTAR MSR, an architectural MSR used to configure the target of address for entry into the kernel by the SYSENTER instruction. Some of the bypass techniques for earlier generations of PatchGuard relied on switching the IA32_LSTAR MSR to the attacker code. That basically means that the attacker code will be run before the actual kernel code on every entry to the kernel, giving the attacker pretty much full control in a manner transparent to the operating system.
My analysis methodology was fairly simple – I used Cyvera’s proprietary kernel instrumentation technology to instrument all access attempts to the IA32_LSTAR MSR which is obviously one of the MSRs that I expected to be protected. I waited for a while but surprisingly, no accesses were made to that MSR for 10 minutes after system boot. At this point I considered two options – either there is a bug in our instrumentation engine (Inconceivable! I never write buggy code!), I hooked the wrong MSR (Inconceivable! I never have a typo!) or PatchGuard actually didn’t trigger in spite it being documented. After several attempts to fix the bugs I obviously didn’t make I went to lunch while pondering these deep questions. I left my instrumentation running and monitoring the kernel. Coming back from a healthy lunch I found a nice surprise – during the time I was at lunch the IA32_LSTAR MSR was accessed twice per each hardware thread, in approximately 30 minute intervals (I also took it as additional proof to my belief that my code is perfect and I never have typos…).
Since the frequency is fairly slow it takes a lot of time I didn’t want to spend to get a big sample. The chart below shows the time (in minutes) between accesses to LSTAR_MSR over one whole night. As you can see in Figure 1 below, while not perfect there appears to be some bias that an attacker might be able to manipulate. Even if not relying on bias, knowing that the MSR check frequency is in the range of 29 to 34 minutes an attacker can take advantage of that.
An interesting occurrence in my observations that I have not been able to reproduce was one time where the frequency of checks was higher – every 15-16 minutes approximately. I have tried to understand this and reading Skywing’s analysis of PatchGuard v3 from September 2007 I noticed the possible launch of a second PatchGuard context during boot that is randomized. If so, it would appear that:
- There is a strong bias against the second context of PatchGuard.
- The frequency of PatchGuard calls in each context is more or less the same for each context
- There might be some link between contexts, sampling at exactly twice the regular interval does not seem random (however, a larger sample – which I do not have yet – is required to prove this)
Figure 2 shows the raw results of the one high frequency instance I ran into so far:
The next step was to look at the source addresses of the calls in memory to understand where PatchGuard “lives”. The first interesting thing I noticed about those was that the source value of the instruction pointer address kept changing (as you can see in the raw data above). I was hoping to see some obvious bias or predictability in the addresses to make it interesting but I could not notice a clear pattern. I tried to create a quick graphical analysis shown below in Figure 3 but it came to nothing as well.
This is the end of this report for now. I hope this helps someone and that it motivates you to share some more basic research on PatchGuard with the community.
To be continued…?