Uninformed: Informative Information for the Uninformed

Vol 8» 2007.Sep

Executing PatchGuard Without SEH

One 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
  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
KiTimerDispatch endp