 |
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.
|