|Informative Information for the Uninformed|
A theoretical approach that has not been tested that could be used to disable PatchGuard would involve using some heuristic algorithm to locate the timer context associated with PatchGuard. To develop such an algorithm, it is necessary to take into account what is known about the way the timer DPC routine is set up. First, it is known that the DeferredRoutine associated with the DPC will point to one of nt!KiScanReadyQueues, nt!ExpTimeRefreshDpcRoutine, or nt!ExpTimeZoneDpcRoutine. Unfortunately, the addresses associated with these routines cannot be directly determined since they are not exported, but regardless, this knowledge could be of use. The second thing that is known is that the DeferredContext associated with the DPC will be set to an invalid pointer. It is also known that at offset 0x88 from the start of the timer structure is the word 0x1131. Given sufficient research, it is also likely that other contextual references could be found in relation to the timer that would provide enough data to deterministically identify the PatchGuard timer.
However, the problem is finding a way able to enumerate timers in the first place. In this case, the un-exported address of the timer list would have to be extracted in order to be able to enumerate all of the active timers. While there are some indirect methods through which this information could be extracted, such as by disassembling some functions that make reference to it, the mere fact of depending on some method of locating un-exported symbols is something that will likely lead to unstable code.
Another option that would not require the location of un-exported symbols would be to find some mechanism by which the address space can be searched, starting at nt!MmNonPagedPoolStart, using the heuristic matching requirements described above. Given the right set of parameters for the search, it seems likely that it would be possible to reliably and deterministically locate the timer structure. However, there is certainly a race condition waiting to happen under this model given that the timer routine could be dispatched immediately after locating it but prior to canceling it. To surmount this, the thread doing the searching would need to raise to a higher IRQL and possibly disable other processors during the time that it is doing its search.
Regardless, given the ability to locate the timer structure, it should be as simple as calling nt!KeCancelTimer to abort the PatchGuard verification routine and disable it entirely. If possible, such an approach would be very optimal because it would require no patching of code.
If such a technique were to be proven feasible, Microsoft would have to do one of two things to break it. First, they could identify the matching criteria being used by drivers and ensure that the assumptions made are no longer safe, thus making it impossible to locate the timer structure using the existing set of matching parameters. Alternatively, Microsoft could change the mechanism by which the PatchGuard verification routine is executed such that it does not make use of a timer DPC routine. The latter is most likely less preferable than the former as it would require a relatively significant redesign and reconsideration of the techniques used to misdirect and obfuscate the PatchGuard verification phase.