Uninformed: Informative Information for the Uninformed

Vol 8» 2007.Sep


DPC Exception Handler Patching

One of the changes introduced in PatchGuard 3 over PatchGuard 2 was a slight change to the protocol used to invoke the first stage of the decryption process. Specifically, all callers of an encrypted PatchGuard context now include a static 8-byte string (of instruction opcodes) that is xor'd with a value at the start of the PatchGuard context to form the initial decryption key.

The reasons for making this change over the original behavior are unclear to the author, but it unfortunately represents an easy target for disabling PatchGuard, as the string itself (0x8513148113148F0) is fairly unique and unlikely to appear outside of PatchGuard in terms of kernel code. Furthermore, all PatchGuard callers, including all ten of the repurposed DPC routine exception handlers and the non-paged pool memory DPC adapter (if used) reference the string with no obfuscation to speak of. This presents an extremely easy, fingerprint-based approach to disabling PatchGuard. By scanning non-paged pool space for this string, as well as kernel code regions, it is trivially easy to locate an instruction in the middle of the every single code path responsible for invoking PatchGuard's check context.

After the instructions referencing the 8-byte string have been located, it is trivial to patch them to execute an unwind out of the exception handler logic (or in the case of the non-paged pool memory code, simply return directly). Such an attack prevents PatchGuard from ever starting, and furthermore has the advantage of a minimum of additional supporting logic required (when compared to many of the other bypass techniques outlined in this article).

It would be trivial for Microsoft to disable this technique. The recommendation of the author would be to get rid of the static 8-byte string referenced in every PatchGuard caller. Ironically, PatchGuard 2 necessarily has a similar 4-byte string (which is also still used in PatchGuard 3), representing the initial instruction of the first stage decryption stub. Unlike with PatchGuard 3, however, PatchGuard 2 takes care to obfuscate the process of writing the opcode string out to the PatchGuard context, so that one cannot simply use a single blanket fingerprint to cover all cases. The change made in PatchGuard 3 completely blows this work out of the water, so to speak, and it has the added advantage of being twice as large as a value to fingerprint as well.