|Informative Information for the Uninformed|
Next: Bypass Mechanisms and Countermeasures Up: Additional Protection Mechanisms Previous: Two-Stage Code Deobfuscation Contents
Given PatchGuard's penchant for blocking attempts to patch the kernel, one would think that all kernel code is essentially expected to be fixed in stone at boot time. However, this is not really the case. There are a number of approved kernel patches that PatchGuard supports. For example, several functions (such as SwapContext) can be patched in approved ways if hypervisor support is enabled. In the case of SwapContext, for instance, a runtime patch is made to redirect execution to EnlightenedSwapContext through a jump instruction being written to the start of the routine. PatchGuard appears to detect and permits patches to these functions through special exemptions (one can observe the address of functions such as SwapContext being stored in the PatchGuard context at initialization time, presumed to be for such a purpose).
The code responsible for checking the integrity of the SwapContext patch is provided below. Because the check ensures that a branch can only occur to EnlightenedSwapContext, it would be difficult to utilize this code to perform an arbitrary patch at SwapContext.
cmp rdi, [rbx+PATCHGUARD_CONTEXT.SwapContext] jnz short NotSwapContextExemption cmp byte ptr [rdi], 0EBh ; 'd' ; backward jmps (short) jnz short NotSwapContextExemption cmp byte ptr [rdi+1], 0F9h ; '·' jnz short NotSwapContextExemption cmp byte ptr [rdi-5], 0E9h ; 'T' ; jmp (long) jnz short NotSwapContextExemption mov rcx, [rbx+PATCHGUARD_CONTEXT.EnlightenedSwapContext] movsxd rax, dword ptr [rdi-4] sub rcx, rdi cmp rax, rcx jz short BadSwapContextHook
There also exists a second set of patches that PatchGuard must allow for compatibility with older processors. Very early releases of x64 processors by Intel did not implement the prefetch instruction, and so the kernel has support for detecting an illegal opcode fault on a prefetch instruction, and reacting by patching out the prefetch opcode on-the-fly. However, this sort of on-the-fly patching is not normally permitted by PatchGuard (for obvious reasons), at least not without special support. During initialization, PatchGuard generates some code that executes a prefetch operation, and then checks whether the the count of patched prefix instructions was incremented after executing the patch code. Assuming that the processor is an older model without prefetch support, then a special exemption (the "prefetch whitelist") is activated the exempts a list of RVAs from the image base from PatchGuard's checks. This list of RVAs is stored in a binary resource appended to ntoskrnl.exe (named "PREFETCHWLIST").
The code for detecting if the prefetch exemption should be enabled at boot time is as follows (the result of the check is, for Windows Server 2008 Beta 3, stored at offset 2B1 into the PatchGuard context):
call KeGetPrcb mov ecx, 2 cmp [rax+63Dh], cl ; Prcb->CpuVendor mov [rsp+0EC8h+var_D48], rax jnz short SkipEnablePrefetchPatchExemption lea rdx, [rsi+214h] ; PrefetchRoutineCode mov dword ptr [rdx], 0C3090D0Fh ; prefetch [rcx] ; ret mov ebx, cs:KiOpPrefetchPatchCount lea rcx, [rsp+0EC8h+arg_18] call rdx mov ecx, cs:KiOpPrefetchPatchCount cmp ebx, ecx jz short SkipEnablePrefetchPatchExemption mov [rsi+2B1h], dil ; EnablePrefetchPatchExemption SkipEnablePrefetchPatchExemption: ; ; Initialization continues ... ; mov eax, 100000h