Uninformed: Informative Information for the Uninformed

Vol 3» 2006.Jan


Obfuscating the PatchGuard Contexts

In order to make it more challenging to locate the PatchGuard contexts in memory, each context is XOR'd with a randomly generated 64-bit key. This is accomplished by calling the function that has been labeled nt!PgEncryptContext that inline XOR's the supplied context buffer and then returns the XOR key that was used to encrypt it. This function is prototyped as shown below:

ULONG64 PgEncryptContext(
    IN OUT PPATCHGUARD_CONTEXT Context);

After nt!KiInitializePatchGuard has initialized all of the individual sub-contexts, the next thing that it does is encrypt the primary PatchGuard context. To accomplish this, it first makes a copy of the context on the stack so that it can be referenced in plain-text after being encrypted. The reason the plain-text copy is needed is so that the verification routine can be queued for execution, and in order to do that it is necessary to reference some of the attributes of the context structure. This is discussed more in the following section. After the copy has been created, a call is made to nt!PgEncryptContext passing the primary PatchGuard context as the first argument. Once the verification routine has been queued for execution, the plain-text copy is no longer needed and is set back to zero in order to ensure that no reference is left in the clear. The pseudo code below illustrates this behavior:

PATCHGUARD_CONTEXT LocalCopy;
ULONG64 XorKey;

memmove(
    &LocalCopy,
    Context,
    sizeof(PATCHGUARD_CONTEXT)); // 0x1b8

XorKey = PgEncryptContext(
    Context);

... Use LocalCopy for verification routine queuing ...

memset(
    &LocalCopy,
    0,
    sizeof(LocalCopy));