Uninformed: Informative Information for the Uninformed

Vol 6» 2007.Jan

Self-Decrypting and Mutating System Integrity Check Routine

PatchGuard version 2 also inherits the capability to encrypt its datastructures and executable code in-memory from version 1. This is a defensive mechanism that intends to make it difficult for an attacker to perform a classic egghunt style search, wherein the attacker has devised an identifiable signature for PatchGuard data structures that can be used to locate it in an exhaustive non-paged-pool memory scan. From this perspective, the obfuscation and encryption of PatchGuard code and data structures that are dynamically allocated is still a reasonably strong defensive mechanism. Unfortunately for Microsoft, though, some of the data structures linking to PatchGuard are internal system structures (such as a KDPC and associated KTIMER used to kick off PatchGuard execution). This presents a weakness that could be potentially used to identify PatchGuard structures in memory (which will be explored in more detail later).

The encryption of PatchGuard's internal context structures was covered by Uninformed's original paper [2] on the subject. However, the mechanism by which PatchGuard obfuscates its system integrity checking and validation routines was not discussed. This mechanism is novel enough to warrant some explanation. The technique used to obfuscate PatchGuard's executable code in-memory involves two layers of decryption/deobfuscation functions, each of which decrypts the next layer. After both layers have run their course, PatchGuard's validation routines are plaintext in memory and are then directly executed.

The first decryption layer is the code block that is called from the repurposed DPC routine selected by PatchGuard at boot time. Its job is to decrypt itself (in 8 byte chunks, starting with the second instruction in the function). After the decryption of the this code block is complete, the decryption stub continues on to decrypt a second code block (the actual PatchGuard validation routine). When this second decryption/deobfuscation cycle is completed, the decryption stub then executes the actual PatchGuard system integrity check routine.

As noted above, the first task for the decryption stub is to decrypt itself. Except for the first instruction of the stub, the entire routine is encrypted when entered. The first instruction encrypts itself and decrypts the next instruction. The following instruction decrypts the next two instructions, and soforth. This is accomplished by a series of four byte long instructions that xor an eight byte quantity with a decryption key (initially starting at the current instruction pointer - here, rcx and rip always have the same value. An example of how this process works is illustrated below:

; rcx: Address of the decryption stub (same as rip)
; rdx: Decryption key
Breakpoint 5 hit
fffff800`0112c98b ff5538          call    qword ptr [rbp+38h]
0: kd> u poi(rbp+38)
; Note that beyond the first instruction, the decryption stub is initially seemingly
; garbage data (though it has an apparent pattern to it, since it is merely obfuscated
; by xor).
fffffadf`f6e6d55d f0483111        lock xor qword ptr [rcx],rdx
fffffadf`f6e6d561 88644d68        mov     byte ptr [rbp+rcx*2+68h],ah
fffffadf`f6e6d565 62              ???
fffffadf`f6e6d566 d257df          rcl     byte ptr [rdi-21h],cl
fffffadf`f6e6d569 88644d78        mov     byte ptr [rbp+rcx*2+78h],ah
fffffadf`f6e6d56d 62              ???
fffffadf`f6e6d56e d257ef          rcl     byte ptr [rdi-11h],cl
fffffadf`f6e6d571 88644d48        mov     byte ptr [rbp+rcx*2+48h],ah
0: kd> t
fffffadf`f6e6d55d f0483111        lock xor qword ptr [rcx],rdx
0: kd> r
; Note the initial input arguments.  rcx points to the decryption stub's first
; instruction (same as rip), and rdx is the decryption key.
rax=fffffadff6e6d55d rbx=fffff8000116d894 rcx=fffffadff6e6d55d
rdx=601c55c0cf06e32a rsi=fffff800003c7ad0 rdi=0000000000000003
rip=fffffadff6e6d55d rsp=fffff800003c51f8 rbp=fffff800003c7ad0
 r8=0000000000000000  r9=0000000000000000 r10=0000000001c7111e
r11=fffff800003c54c0 r12=fffff8000116d858 r13=fffff800003c5370
r14=fffff80001000000 r15=fffff800003c60a0
iopl=0         nv up ei pl zr na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
fffffadf`f6e6d55d f0483111        lock xor qword ptr [rcx],rdx ds:002b:fffffadf`f6e6d55d=684d6488113148f0

; After allowing the decryption of the stub to progress, we see the stub in its executable
; form.  The first instruction is initially re-encrypted after executed, but a later
; instruction in the decryption stub returns the initial instruction to its executable,
; plaintext form.

0: kd> u FFFFFADFF6E6D55D
; The `lock' prefix is used to create a four byte instruction when there
; is no immediate offset specified (a MASM limitation, as the assembler
; will convert a zero offset into the shorter form with no immediate
; offset operand).
fffffadf`f6e6d55d f0483111        lock xor qword ptr [rcx],rdx
fffffadf`f6e6d561 48315108        xor     qword ptr [rcx+8],rdx
fffffadf`f6e6d565 48315110        xor     qword ptr [rcx+10h],rdx
fffffadf`f6e6d569 48315118        xor     qword ptr [rcx+18h],rdx
fffffadf`f6e6d56d 48315120        xor     qword ptr [rcx+20h],rdx
fffffadf`f6e6d571 48315128        xor     qword ptr [rcx+28h],rdx
fffffadf`f6e6d575 48315130        xor     qword ptr [rcx+30h],rdx
fffffadf`f6e6d579 48315138        xor     qword ptr [rcx+38h],rdx
0: kd> u
fffffadf`f6e6d57d 48315140        xor     qword ptr [rcx+40h],rdx
fffffadf`f6e6d581 48315148        xor     qword ptr [rcx+48h],rdx
; Because the initial instruction was re-encrypted after it was executed,
; we need to decrypt it again.
fffffadf`f6e6d585 3111            xor     dword ptr [rcx],edx
fffffadf`f6e6d587 488bc2          mov     rax,rdx
fffffadf`f6e6d58a 488bd1          mov     rdx,rcx
fffffadf`f6e6d58d 8b4a4c          mov     ecx,dword ptr [rdx+4Ch]
; The following is the second stage decryption loop.  It's purpose is to
; decrypt a code block following the current decryption stub in memory.
; This code block is then executed (it is responsible for performing the
; actual PatchGuard system verification checks).

fffffadf`f6e6d590 483144ca48      xor     qword ptr [rdx+rcx*8+48h],rax
fffffadf`f6e6d595 48d3c8          ror     rax,cl
0: kd> u
fffffadf`f6e6d598 e2f6            loop    fffffadf`f6e6d590
; After decryption of the second block is completed, we'll execute it
; by jumping to it.  Doing so kicks off the system verification routine
; that verifies system integrity, arranging for a bug check if not,
; otherwise arranging for itself to be executed again several minutes
; later.
fffffadf`f6e6d59a 8b8288010000    mov     eax,dword ptr [rdx+188h]
fffffadf`f6e6d5a0 4803c2          add     rax,rdx
fffffadf`f6e6d5a3 ffe0            jmp     rax

Prior to returning control, the verification routine re-encrypts itself so that it does not remain in plaintext after the first invocation. In addition, PatchGuard also re-randomizes the key used to encrypt and decrypt the PatchGuard validation routine on each execution, such that a would-be attacker has a frequently mutating target. Due to this behavior, the PatchGuard validation routine changes appearance (in encrypted form) in-memory every few minutes, which is the period of PatchGuard's validation checks. While this is perhaps an admirable effort on Microsoft's part as far as interesting obfuscation techniques go, it turns out that there are much easier avenues of attack that can be used to disable PatchGuard without having to involve oneself in the search of a target that alters its appearance in-memory every few minutes.