Informative Information for the Uninformed | ||||||||||||||
|
||||||||||||||
Next: Randomized Call Frames in
Up: Protection Improvements
Previous: Filtering of Exception Codes
Contents
Executing PatchGuard Without SEHOne recurring theme that has continued to remain a staple for PatchGuard since its inception is the use of structured exception handling to obfuscate the calls to PatchGuard. The intention here is to use the many differences of SEH between x64 and x86, and the lack of disassembler support for x64 SEH to make it difficult to understand what is happening when calls to PatchGuard are being made. Ironically, this use of x64 SEH as an obfuscation mechanism has been a catalyst for much of the author's research [2] into Windows x64 SEH. Today, it is the author's opinion that x64 exception handling is now publicly documented to an extent that is comparable (or even exceeds) that available for x86 SEH. Although x64 SEH may have been useful as an obfuscation technology initially, it had clearly worked its way up to a major liability after PatchGuard 2 had been released. This is due to the fact that SEH-related aspects of PatchGuard had been successfully used to defeat PatchGuard on multiple occasions. With the advent of PatchGuard 3, the authors of PatchGuard siezed the opportunity to extricate themselves in some respect from the liability that x64 SEH had become. PatchGuard 3 introduces a special mode of operation that allows it to function without using SEH. This is a significant change (and improvement) with respect to how PatchGuard has traditionally operated. It eliminates a major class of single points of failure in that the exception dispatching path is particularly vulnerable to external interference in terms of third party drivers intercepting SEH dispatching before control is transferred to actual exception handlers. The SEH-less mode of PatchGuard 3 operates by copying a small section of code into non-paged pool memory (as part of a PatchGuard context block). This code is then referenced by a timer object's DeferredRoutine at the non-paged pool location in question. The code referred to by the timer object is essentially a stripped down version of what happens when any of the re-purposed DPC routines are invoked by PatchGuard: it sets up a call to the first stage self-decrypting stub that ultimately calls the system check routine. By completely eliminating SEH as a launch vector for PatchGuard, many bypass techniques that hinged on being able to catch PatchGuard in the SEH dispatching code path are completely invalidated. In an example of defense in depth in terms of software protection systems, the old, SEH-based system is still retained (with the previously mentioned modifications), such that a would-be attacker now has multiple isolated launch vectors that he or she must deal with in order to block PatchGuard from executing. Annotated disassembly of the direct call routine that is copied to non-paged pool and invoked without SEH is presented below:
KiTimerDispatch proc near pushf sub rsp, 20h mov eax, [rsp+28h+var_8] xor r9d, r9d xor r8d, r8d mov [rsp+28h+arg_0], rax ; [rcx+40] -> PatchGuard Decryption Key mov rax, [rcx+40h] mov rcx, 0FFFFF80000000000h xor rax, rdx ; Form a valid address for the PatchGuard context block by ; xoring the decryption key with the DeferredContext ; argument. or rax, rcx ; Set the initial code for the stage 1 self-decrypting stub. mov rcx, 8513148113148F0h mov rdx, [rax] mov dword ptr [rax], 113148F0h xor rdx, rcx mov rcx, rax ; Call the stage 1 self-decrypting stub. call rax add rsp, 20h pop rcx retn KiTimerDispatch endp
|