|
General Detect Bit Interception
One of PatchGuard's anti-debug mechanisms relates to debug registers.
Specifically, PatchGuard attempts to clear Dr7 (the debug
control register) in an attempt to disable all debug-register-based
breakpoints, as one of the first tasks upon entering the system integrity
check routine. This presents an inherent weakness within PatchGuard, as there
is support built-in to the processor that allows one to detect (and intercept)
direct accesses to any of the debug registers. This support is primarily
legacy, intended for so-called in-circuit emulators (ICEs), which were
special hardware components that acted as a true hardware-based debugger by
allowing one to control a processor from outside the context of the system
entirely, in essence truly isolating the debugger from the operating system
and any programs running under it. This support is embodied in the General
Detect bit in Dr7, which when set, causes a debug trap to be generated on any
successful access to a debug register. This is significant in that it
provides a way for an attacker to trap PatchGuard's access to Dr7 (zeroing
it), which in effect provides a means to pinpoint the exact location of
PatchGuard's system integrity routine in-memory, in-plaintext. Furthermore,
it gives an attacker the possibility of making any alterations desired to the
execution context at the very start of the system integrity check, which could
be trivially used in order to simply implement an immediate return out of the
system integrity check logic without actually verifying the system's integrity
(as dr7 is zeroed before any integrity checks are performed). This approach
effectively turns another one of PatchGuard's protection mechanisms against
it, utilizing the anti-debug-register behavior to detect (and block)
PatchGuard.
The general idea behind this approach is similar to that described
in technique 4.4. In the same fashion as in technique
4.4, an implementor of this approach is required to gain
control of the debug trap handler. For this task, any of the
proposed approaches in technique 4.4 may be used. After
control of the debug trap handler is established, an attacker must
then set the general detect bit in Dr7 and wait for
PatchGuard to access the debug registers. It should be noted that
during the legitimate course of execution, the kernel itself will
often directly access debug registers, such as during context
switches or if NtSetContextThread/NtGetContextThread are invoked.
Any such implementation of this technique must be able to
differentiate between PatchGuard's accesses of the debug registers
and legitimate accesses. This could be trivially implemented by
checking if the RIP value at the time of the trap was within a valid
kernel image or not, as the PatchGuard system integrity check
routine resides in dynamically allocated non-paged pool and not
within the confines of the kernel images in-memory.
When the debug trap handler is invoked as a result of PatchGuard zeroing
Dr7, then the appropriate action (which could be as trivial as simply
executing a hard return out of the system integrity check routine) can be
taken by the third-party driver wishing to disable PatchGuard.
Like the techniques that capitalize on PatchGuard's use of SEH to obfuscate
the call to the system integrity check routine, this approach relies on using
one of PatchGuard's defensive mechanisms against it. The most obvious counter
would be to thus remove the behavior of zeroing debug registers. However,
disabling this behavior may not be very desirable, as it would then be very
easy to detect PatchGuard by, say, setting a read breakpoint on kernel code
and waiting for PatchGuard to perform a read. Since reads of kernel code (as
opposed to execute fetches) are fairly atypical, this would open up another
easy mechanism by which PatchGuard could be bypassed.
The best course of action by Microsoft here would be to make it as difficult
as possible to differentiate between legitimate accesses to debug registers
and PatchGuard's own accesses, although this is likely to not be very doable.
Strengthening the debug trap path against interception by placing additional
validation checks over that code path might also be useful in countering this
technique, although likely to only a limited, easily-bypassable extent.
|