Uninformed: Informative Information for the Uninformed

Vol 6» 2007.Jan

Patching the Kernel Timer DPC Dispatcher

Currently, PatchGuard utilizes a timer with an associated DPC to transfer control to a preselected one of ten possible legitimate DPC routines that have been slightly modified for use with PatchGuard. Because third party kernel drivers are given a documented and exported interface to create timers with associated DPC routines, this represents a weakness in PatchGuard, in that it presents an easily-detectable location in the critical execution path for PatchGuard's system integrity check routine that could be relatively easily compromised by a third-party driver. This technique focuses on gaining control of the timer DPC dispatcher, with the goal of detecting when the PatchGuard DPC is about to be dispatched. When the PatchGuard DPC is detected, then the third-party driver could skip over the PatchGuard DPC routine entirely, thus disabling PatchGuard.

In order to accomplish this, a third party driver would need to locate the exact instruction within the kernel timer DPC dispatcher that is responsible for making calls to timer DPC routines. Fortunately, this is a fairly easy task for a driver, as the interfaces for creating timers with associated DPCs and DPC routines are documented and exported. Specifically, a third party driver could queue a timer DPC, and then record address of the DPC dispatcher routine via inspection of the return address of the timer DPC routine when it is called. From there, the driver can derive the address of the call instruction responsible for making the call to the DPC routine associated with a DPC object that is associated with a timer.

At this point, all a third party driver needs to do is patch the call instruction in the DPC dispatcher to transfer execution control to the driver's code. From there, the driver can filter all timer DPCs for the PatchGuard DPC routine (perhaps by looking for a bogus kernel address in DeferredContext, paired with a DPC routine that is within the confines of the kernel image in-memory). When the PatchGuard DPC is detected, then the driver can decline to call the DPC routine and instead simply return control to the kernel DPC dispatcher after the call instruction in the logical original instruction stream. This effectively prevents PatchGuard from ever running the system integrity check, which again gives the driver free reign to patch the kernel without fear of intervention by PatchGuard.

In the author's opinion, the best way to prevent this approach is to use a multitude of different mechanisms to kick off execution of the PatchGuard check routine. For example, a dedicated thread waiting on a timer could also be used, or a frequently-called system routine could be modified to periodically make calls to PatchGuard. As long as calls to PatchGuard are funneled through one location, such as the timer DPC dispatcher, the entire PatchGuard integrity check system is at risk of being trivially bypassed in one fell swoop by third party drivers.