Uninformed: Informative Information for the Uninformed

Vol 3» 2006.Jan


Initializing PatchGuard

The initialization of PatchGuard is multi-faceted, but it all has to start somewhere. In this case, the initialization of PatchGuard starts in a function with a symbol name that has nothing to do with anti-patch protections at all. In fact, it's named KiDivide6432 and the only thing that it does is a division operation as shown in the code below:

ULONG KiDivide6432(
    IN ULONG64 Dividend,
    IN ULONG Divisor)
{
    return Dividend / Divisor;
}

Though this function may look innocuous, it's actually the first time PatchGuard attempts to use misdirection to hide its actual intentions. In this case, the call to nt!KiDivide6432 is passed a dividend value from nt!KiTestDividend. The divisor is hard-coded to be 0xcb5fa3. It appears that this function is intended to masquerade as some type of division test that ensures that the underlying architecture supports division operations. If the call to the function does not return the expected result of 0x5ee0b7e5, nt!KeInitSystem will bug check the operating system with bug check code 0x5d which is UNSUPPORTED_PROCESSOR as shown below:

nt!KeInitSystem+0x158:
fffff800`014212c2 488b0d1754d5ff   mov     rcx,[nt!KiTestDividend]
fffff800`014212c9 baa35fcb00       mov     edx,0xcb5fa3
fffff800`014212ce e84d000000       call    nt!KiDivide6432
fffff800`014212d3 3de5b7e05e       cmp     eax,0x5ee0b7e5
fffff800`014212d8 0f8519b60100     jne     nt!KeInitSystem+0x170

...

nt!KeInitSystem+0x170:
fffff800`0143c8f7 b95d000000       mov     ecx,0x5d
fffff800`0143c8fc e8bf4fc0ff       call    nt!KeBugCheck

When attaching with local kd, the value of nt!KiTestDividend is found to be hardcoded to 0x014b5fa3a053724c such that doing the division operation, 0x014b5fa3a053724c divided by 0xcb5fa3, produces 0x1a11f49ae. That can't be right though, can it? Obviously, the code above indicates that any value other than 0x5ee0b7e5 will lead to a bug check, but it's also equally obvious that the machine does not bug check on boot, so what's going on here?

The answer involves a good old fashion case of ingenuity. The result of the the division operation above is a value that is larger than 32 bits. The AMD64 instruction set reference manual indicates that the div instruction will produce a divide error fault when an overflow of the quotient occurs[2]. This means that as long as nt!KiTestDividend is set to the value described above, a divide error fault will be triggered causing a hardware exception that has to be handled by the kernel. This divide error fault is what actually leads to the indirect initialization of the PatchGuard subsystem. Before going down that route, though, it's important to understand one of the interesting aspects of the way Microsoft did this.

One of the interesting things about nt!KiTestDividend is that it's actually unioned with an exported symbol that is used to indicate whether or not a debugger is, well, present. This symbol is named nt!KdDebuggerNotPresent and it overlaps with the high-order byte of nt!KiTestDividend as shown below:

lkd> dq nt!KiTestDividend L1
fffff800`011766e0  014b5fa3`a053724c
lkd> db nt!KdDebuggerNotPresent L1
fffff800`011766e7  01

The nt!KdDebuggerNotPresent global variable will be set to zero if a debugger is present. If a debugger is not present, the value will be one (default). If the above described division operation is performed while a debugger is attached to the system during boot, which would equate to dividing 0x004b5fa3a053724c by 0xcb5fa3, the resultant quotient will be the expected value of 0x5ee0b7e5. This means that if a debugger is attached to the system prior to the indirect initialization of the PatchGuard protections, then the protections will not be initialized because the divide error fault will not be triggered. This coincides with the documented behavior and is intended to allow driver developers to continue to be able to set breakpoints and perform other actions that may indirectly modify monitored regions of the kernel in a debugging environment. However, this only works if the debugger is attached to the system during boot. If a developer subsequently attaches a debugger after PatchGuard has initialized, then the act of setting breakpoints or performing other actions may lead to a bluescreen as a result of PatchGuard detecting the alterations. Microsoft's choice to initialize PatchGuard in this manner allows it to transparently disable protections when a debugger is attached and also acts as a means of hiding the true initialization vector.

With the unioned aspect of nt!KiTestDividend understood, the next step is to understand how the divide error fault actually leads to the initialization of the PatchGuard subsystem. For this aspect it is necessary to start at the places that all divide error faults go: nt!KiDivideErrorFault.

The indirect triggering of nt!KiDivideErrorFault leads to a series of function calls that eventually result in nt!KiOp_Div being called to handle the divide error fault for the div instruction. The nt!KiOp_Div routine appears to be responsible for preprocessing the different kinds of divide errors, like divide by zero. Although it may look normal at first glance, nt!KiOp_Div also has a darker side. The stack trace that leads to the calling of nt!KiOp_Div is shown below3.1:

kd> k
Child-SP          RetAddr           Call Site
fffffadf`e4a15f90 fffff800`010144d4 nt!KiOp_Div+0x29
fffffadf`e4a15fe0 fffff800`01058d75 nt!KiPreprocessFault+0xc7
fffffadf`e4a16080 fffff800`0104172f nt!KiDispatchException+0x85
fffffadf`e4a16680 fffff800`0103f5b7 nt!KiExceptionExit
fffffadf`e4a16800 fffff800`0142132b nt!KiDivideErrorFault+0xb7
fffffadf`e4a16998 fffff800`014212d3 nt!KiDivide6432+0xb
fffffadf`e4a169a0 fffff800`0142a226 nt!KeInitSystem+0x169
fffffadf`e4a16a50 fffff800`01243e09 nt!Phase1InitializationDiscard+0x93e
fffffadf`e4a16d40 fffff800`012b226e nt!Phase1Initialization+0x9
fffffadf`e4a16d70 fffff800`01044416 nt!PspSystemThreadStartup+0x3e
fffffadf`e4a16dd0 00000000`00000000 nt!KxStartSystemThread+0x16

The first thing that nt!KiOp_Div does prior to processing the actual divide fault is to call a function named nt!KiFilterFiberContext. This function seems oddly named not only in the general sense but also in the specific context of a routine that is intended to be dealing with divide faults. By looking at the body of nt!KiFilterFiberContext, its intentions quickly become clear:

nt!KiFilterFiberContext:
fffff800`01003ac2 53               push    rbx
fffff800`01003ac3 4883ec20         sub     rsp,0x20
fffff800`01003ac7 488d0552d84100   lea     rax,[nt!KiDivide6432]
fffff800`01003ace 488bd9           mov     rbx,rcx
fffff800`01003ad1 4883c00b         add     rax,0xb
fffff800`01003ad5 483981f8000000   cmp     [rcx+0xf8],rax
fffff800`01003adc 0f855d380c00     jne     nt!KiFilterFiberContext+0x1d
fffff800`01003ae2 e899fa4100       call    nt!KiDivide6432+0x570

It appears that this chunk of code is designed to see if the address that the fault error occurred at is equal to nt!KiDivide6432 + 0xb. If one adds 0xb to nt!KiDivide6432 and disassembles the instruction at that address, the result is:

nt!KiDivide6432+0xb:
fffff800`0142132b 41f7f0           div     r8d

This coincides with what one would expect to occur when the quotient overflow condition occurs. According to the disassembly above, if the fault address is equal to nt!KiDivide6432 + 0xb, then an unnamed symbol is called at nt!KiDivide6432 + 0x570. This unnamed symbol will henceforth be referred to as nt!KiInitializePatchGuard, and it is what drives the set up of the PatchGuard subsystem.

The nt!KiInitializePatchGuard routine itself is quite large. It handles the initialization of the contexts that will monitor certain system images, the SSDT, processor GDT/IDT, certain critical MSRs, and certain debugger-related routines. The very first thing that the initialization routine does is to check to see if the machine is being booted in safe mode. If it is being booted in safe mode, the PatchGuard subsystem will not be enabled as shown below:

nt!KiDivide6432+0x570:
fffff800`01423580 4881ecd8020000   sub     rsp,0x2d8
fffff800`01423587 833d22dfd7ff00   cmp     dword ptr [nt!InitSafeBootMode],0x0
fffff800`0142358e 0f8504770000     jne     nt!KiDivide6432+0x580

...

nt!KiDivide6432+0x580:
fffff800`0142ac98 b001             mov     al,0x1
fffff800`0142ac9a 4881c4d8020000   add     rsp,0x2d8
fffff800`0142aca1 c3               ret

Once the safe mode check has passed, nt!KiInitializePatchGuard begins the PatchGuard initialization by calculating the size of the INITKDBG section in ntoskrnl.exe. It accomplishes this by passing the address of a symbol found within that section, nt!FsRtlUninitializeSmallMcb, to nt!RtlPcToFileHeader. This routine passes back the base address of nt in an output parameter that is subsequently passed to nt!RtlImageNtHeader. This method returns a pointer to the image's IMAGE_NT_HEADERS structure. From there, the virtual address of nt!FsRtlUninitializeSmallMcb is calculated by subtracting the base address of nt from it. The calculated RVA is then passed to nt!RtlSectionTableFromVirtualAddress which returns a pointer to the image section that nt!FsRtlUninitializeSmallMcb resides in. The debugger output below shows what rax points to after obtaining the image section structure:

kd> ? rax
Evaluate expression: -8796076244456 = fffff800`01000218
kd> dt nt!_IMAGE_SECTION_HEADER fffff800`01000218
+0x000 Name             : [8]  "INITKDBG"
+0x008 Misc             : <unnamed-tag>
+0x00c VirtualAddress   : 0x165000
+0x010 SizeOfRawData    : 0x2600
+0x014 PointerToRawData : 0x163a00
+0x018 PointerToRelocations : 0
+0x01c PointerToLinenumbers : 0
+0x020 NumberOfRelocations : 0
+0x022 NumberOfLinenumbers : 0
+0x024 Characteristics  : 0x68000020

The whole reason behind this initial image section lookup has to do with one of the ways in which PatchGuard obfuscates and hides the code that it executes. In this case, code within the INITKDBG section will eventually be copied into an allocated protection context that will be used during the validation phase. The reason that this is necessary will be discussed in more detail later.

After collecting information about the INITKDBG image section, the PatchGuard initialization routine performs the first of many pseudo-random number generations. This code can be seen throughout the PatchGuard functions and has a form that is similar to the code shown below:

fffff800`0142362d 0f31                 rdtsc
fffff800`0142362f 488bac24d8020000     mov     rbp,[rsp+0x2d8]
fffff800`01423637 48c1e220             shl     rdx,0x20
fffff800`0142363b 49bf0120000480001070 mov     r15,0x7010008004002001
fffff800`01423645 480bc2               or      rax,rdx
fffff800`01423648 488bcd               mov     rcx,rbp
fffff800`0142364b 4833c8               xor     rcx,rax
fffff800`0142364e 488d442478           lea     rax,[rsp+0x78]
fffff800`01423653 4833c8               xor     rcx,rax
fffff800`01423656 488bc1               mov     rax,rcx
fffff800`01423659 48c1c803             ror     rax,0x3
fffff800`0142365d 4833c8               xor     rcx,rax
fffff800`01423660 498bc7               mov     rax,r15
fffff800`01423663 48f7e1               mul     rcx
fffff800`01423666 4889442478           mov     [rsp+0x78],rax
fffff800`0142366b 488bca               mov     rcx,rdx
fffff800`0142366e 4889942488000000     mov     [rsp+0x88],rdx
fffff800`01423676 4833c8               xor     rcx,rax
fffff800`01423679 48b88fe3388ee3388ee3 mov     rax,0xe38e38e38e38e38f
fffff800`01423683 48f7e1               mul     rcx
fffff800`01423686 48c1ea03             shr     rdx,0x3
fffff800`0142368a 488d04d2             lea     rax,[rdx+rdx*8]
fffff800`0142368e 482bc8               sub     rcx,rax
fffff800`01423691 8bc1                 mov     eax,ecx

This pseudo-random number generator uses the rdtsc instruction as a seed and then proceeds to perform various bitwise and multiplication operations until the end result is produced in eax. The result of this first random number generator is used to index an array of pool tags that are used for PatchGuard memory allocations. This is an example of one of the many ways in which PatchGuard attempts to make it harder to find its own internal data structures in memory. In this case, it adopts a random legitimate pool tag in an effort to blend in with other memory allocations. The code block below shows how the pool tag array is indexed and where it can be found in memory:

fffff800`01423693 488d0d66c9bdff   lea     rcx,[nt]
fffff800`0142369a 448b848100044300 mov     r8d,[rcx+rax*4+0x430400]

In this case, the random number is stored in the rax register which is used to index the array of pool tags found at nt+0x430400. The fact that the array is referenced indirectly might be seen as another attempt at obfuscation in a bid to make what is occurring less obvious at a glance. If the pool tag array address is dumped in the debugger, all of the pool tags that could possibly be used by PatchGuard can be seen:

lkd> db nt+0x430400
41 63 70 53 46 69 6c 65-49 70 46 49 49 72 70 20  AcpSFileIpFIIrp
4d 75 74 61 4e 74 46 73-4e 74 72 66 53 65 6d 61  MutaNtFsNtrfSema
54 43 50 63 00 00 00 00-10 3b 03 01 00 f8 ff ff  TCPc.....;......

After the fake pool tag has been selected from the array at random, the PatchGuard initialization routine proceeds by allocating a random amount of storage that is bounded at a minimum by the virtual size of the INITKDBG section plus 0x1b8 and at a maximum by the minimum plus 0x7ff. The magic value 0x1b8 that is expressed in the minimum size is actually the size of the data structure that is used by PatchGuard to store context-specific protection information, as will be shown later. The fake pool tag and the random size are then used to allocate storage from the NonPagedPool as shown in the pseudo-code below:

Context = ExAllocatePoolWithTag(
    NonPagedPool,
    (InitKdbgSection->VirtualSize + 0x1b8) + (RandSize & 0x7ff),
    PoolTagArray[RandomPoolTagIndex]);

If the allocation of the context succeeds, the initialization routine zeroes its contents and then starts initializing some of the structure's attributes. The context returned by the allocation will henceforth be referred to as a structure of type PATCHGUARD_CONTEXT. The first 0x48 bytes of the structure are actually composed of code that is copied from the misleading symbol named nt!CmpAppendDllSection. This function is actually used to decrypt the structure at runtime, as will be seen later. After nt!CmpAppendDllSection is copied to the first 0x48 bytes of the data structure, the initialization routine sets up a number of function pointers that are stored within the structure. The routines that it stores the addresses of and the offsets within the PatchGuard context data structure are shown in figure [*].

Offset Symbol
0x48 nt!ExAcquireResourceSharedLite
0x50 nt!ExAllocatePoolWithTag
0x58 nt!ExFreePool
0x60 nt!ExMapHandleToPointer
0x68 nt!ExQueueWorkItem
0x70 nt!ExReleaseResourceLite
0x78 nt!ExUnlockHandleTableEntry
0x80 nt!ExAcquireGuardedMutex
0x88 nt!ObDereferenceObjectEx
0x90 nt!KeBugCheckEx
0x98 nt!KeInitializeDpc
0xa0 nt!KeLeaveCriticalRegion
0xa8 nt!KeReleaseGuardedMutex
0xb0 nt!ObDereferenceObjectEx2
0xb8 nt!KeSetAffinityThread
0xc0 nt!KeSetTimer
0xc8 nt!RtlImageDirectoryEntryToData
0xd0 nt!RtlImageNtHeaders
0xd8 nt!RtlLookupFunctionEntry
0xe0 nt!RtlSectionTableFromVirtualAddress
0xe8 nt!KiOpPrefetchPatchCount
0xf0 nt!KiProcessListHead
0xf8 nt!KiProcessListLock
0x100 nt!PsActiveProcessHead
0x108 nt!PsLoadedModuleList
0x110 nt!PsLoadedModuleResource
0x118 nt!PspActiveProcessMutex
0x120 nt!PspCidTable

The reason that PatchGuard uses function pointers instead of calling the symbols directly is most likely due to the relative addressing mode used in x64. Since the PatchGuard code runs dynamically from unpredictable addresses, it would be impossible to use the relative addressing mode without having to fix up instructions - a task that would no doubt be painful and not really worth the trouble. The authors do not see any particular advantage gained in terms of obfuscation by the use of function pointers stored in the PatchGuard context structure.

After all of the function pointers have been set up, the initialization routine proceeds by picking another random pool tag that is used for subsequent allocations and stores it at offset 0x188 within the PatchGuard context structure. After that, two more random numbers are generated, both of which are used later on during the encryption phase of the structure. One is used as a random number of rotate bits, the other is used as an XOR seed. The XOR seed is stored at offset 0x190 and the random rotate bits value is stored at offset 0x18c.

The next step taken by the initialization routine is to acquire the number of bits that can be used to represent the virtual address space by querying the processor via through the cpuid ExtendedAddressSize (0x80000008) extended function. The result is stored at offset 0x1b4 within the PatchGuard context structure.

Finally, the last major step before initializing the individual protection sub-contexts is the copying of the contents of the INITKDBG section to the allocated PatchGuard context structure. The copy operation looks something like the pseudo code below:

memmove(
    (PCHAR)PatchGuardContext + sizeof(PATCHGUARD_CONTEXT),
    NtImageBase + InitKdbgSection->VirtualAddress,
    InitKdbgSection->VirtualSize);

With the primary portions of the PatchGuard context structure initialized, the next logical step is to initialize the sub-contexts that are specific to the things that are actually being protected.