aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--EfiGuardDxe/PatchNtoskrnl.c101
1 files changed, 97 insertions, 4 deletions
diff --git a/EfiGuardDxe/PatchNtoskrnl.c b/EfiGuardDxe/PatchNtoskrnl.c
index 7cbb77d..1ddb0c8 100644
--- a/EfiGuardDxe/PatchNtoskrnl.c
+++ b/EfiGuardDxe/PatchNtoskrnl.c
@@ -35,6 +35,17 @@ STATIC CONST UINT8 SigKiVerifyScopesExecute[] = {
0x48, 0xB8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE // mov rax, 0FEFFFFFFFFFFFFFFh
};
+// Signature for nt!KiMcaDeferredRecoveryService
+// This function is present since Windows 8.1 and bugchecks the system with bugcode 0x109 after zeroing registers.
+// It is called by KiScanQueues and KiSchedulerDpc, two PatchGuard DPCs which may be queued from various unrelated kernel functions.
+STATIC CONST UINT8 SigKiMcaDeferredRecoveryService[] = {
+ 0x33, 0xC0, // xor eax, eax
+ 0x8B, 0xD8, // mov ebx, eax
+ 0x8B, 0xF8, // mov edi, eax
+ 0x8B, 0xE8, // mov ebp, eax
+ 0x4C, 0x8B, 0xD0 // mov r10, rax
+};
+
// Signature for nt!KiSwInterrupt
// This function is present since Windows 10 and is the interrupt handler for int 20h.
// This interrupt is a spurious interrupt on older versions of Windows, and does nothing useful on Windows 10.
@@ -136,7 +147,7 @@ DisablePatchGuard(
return EFI_LOAD_ERROR;
}
- CONST UINTN Length = SizeOfRawData;
+ UINTN Length = SizeOfRawData;
UINTN Offset = 0;
ZyanU64 InstructionAddress;
ZydisDecodedInstruction Instruction;
@@ -277,14 +288,85 @@ DisablePatchGuard(
}
}
- // Search for KiSwInterrupt (only exists on Windows >= 10)
- UINT8* KiSwInterruptPatternAddress = NULL;
- if (BuildNumber >= 10240)
+ // Search for callers of KiMcaDeferredRecoveryService (only exists on Windows >= 8.1)
+ UINT8* KiMcaDeferredRecoveryServiceCallers[2];
+ ZeroMem(KiMcaDeferredRecoveryServiceCallers, sizeof(KiMcaDeferredRecoveryServiceCallers));
+ if (BuildNumber >= 9600)
{
StartRva = TextSection->VirtualAddress;
SizeOfRawData = TextSection->SizeOfRawData;
StartVa = ImageBase + StartRva;
+ // Search for KiMcaDeferredRecoveryService
+ PRINT_KERNEL_PATCH_MSG(L"== Searching for nt!KiMcaDeferredRecoveryService pattern in .text ==\r\n");
+ UINT8* KiMcaDeferredRecoveryService = NULL;
+ for (UINT8* Address = (UINT8*)StartVa; Address < StartVa + SizeOfRawData - sizeof(SigKiMcaDeferredRecoveryService); ++Address)
+ {
+ if (CompareMem(Address, SigKiMcaDeferredRecoveryService, sizeof(SigKiMcaDeferredRecoveryService)) == 0)
+ {
+ KiMcaDeferredRecoveryService = Address;
+ PRINT_KERNEL_PATCH_MSG(L" Found KiMcaDeferredRecoveryService pattern at 0x%llX.\r\n", (UINTN)KiMcaDeferredRecoveryService);
+ break;
+ }
+ }
+
+ if (KiMcaDeferredRecoveryService == NULL)
+ {
+ PRINT_KERNEL_PATCH_MSG(L" Failed to find KiMcaDeferredRecoveryService.\r\n");
+ return EFI_NOT_FOUND;
+ }
+
+ // Start decode loop
+ Length = SizeOfRawData;
+ Offset = 0;
+ while ((InstructionAddress = (ZyanU64)(StartVa + Offset),
+ Status = ZydisDecoderDecodeBuffer(&Decoder,
+ (VOID*)InstructionAddress,
+ Length - Offset,
+ &Instruction)) != ZYDIS_STATUS_NO_MORE_DATA)
+ {
+ if (!ZYAN_SUCCESS(Status))
+ {
+ Offset++;
+ continue;
+ }
+
+ // Check if this is 'call KiMcaDeferredRecoveryService'
+ ZyanU64 OperandAddress = 0;
+ if (Instruction.mnemonic == ZYDIS_MNEMONIC_CALL &&
+ ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(&Instruction, &Instruction.operands[0], InstructionAddress, &OperandAddress)) &&
+ OperandAddress == (UINTN)KiMcaDeferredRecoveryService)
+ {
+ if (KiMcaDeferredRecoveryServiceCallers[0] == NULL)
+ {
+ KiMcaDeferredRecoveryServiceCallers[0] = (UINT8*)InstructionAddress;
+ }
+ else if (KiMcaDeferredRecoveryServiceCallers[1] == NULL)
+ {
+ KiMcaDeferredRecoveryServiceCallers[1] = (UINT8*)InstructionAddress;
+ break;
+ }
+ }
+
+ Offset += Instruction.length;
+ }
+
+ // Backtrack to function start
+ KiMcaDeferredRecoveryServiceCallers[0] = BacktrackToFunctionStart(KiMcaDeferredRecoveryServiceCallers[0],
+ (UINT8*)(KiMcaDeferredRecoveryServiceCallers[0] - StartVa));
+ KiMcaDeferredRecoveryServiceCallers[1] = BacktrackToFunctionStart(KiMcaDeferredRecoveryServiceCallers[1],
+ (UINT8*)(KiMcaDeferredRecoveryServiceCallers[1] - StartVa));
+ if (KiMcaDeferredRecoveryServiceCallers[0] == NULL || KiMcaDeferredRecoveryServiceCallers[1] == NULL)
+ {
+ PRINT_KERNEL_PATCH_MSG(L" Failed to find KiMcaDeferredRecoveryService callers.\r\n");
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ // Search for KiSwInterrupt (only exists on Windows >= 10)
+ UINT8* KiSwInterruptPatternAddress = NULL;
+ if (BuildNumber >= 10240)
+ {
PRINT_KERNEL_PATCH_MSG(L"== Searching for nt!KiSwInterrupt pattern in .text ==\r\n");
CONST EFI_STATUS FindKiSwInterruptStatus = FindPattern(SigKiSwInterrupt,
0xCC,
@@ -313,6 +395,11 @@ DisablePatchGuard(
*((UINT32*)ExpLicenseWatchInitWorker) = No;
if (KiVerifyScopesExecute != NULL)
*(UINT32*)KiVerifyScopesExecute = No;
+ if (KiMcaDeferredRecoveryServiceCallers[0] != NULL && KiMcaDeferredRecoveryServiceCallers[1] != NULL)
+ {
+ *(UINT32*)KiMcaDeferredRecoveryServiceCallers[0] = No;
+ *(UINT32*)KiMcaDeferredRecoveryServiceCallers[1] = No;
+ }
if (KiSwInterruptPatternAddress != NULL)
SetMem(KiSwInterruptPatternAddress, sizeof(SigKiSwInterrupt), 0x90); // 11 x nop
@@ -331,6 +418,12 @@ DisablePatchGuard(
PRINT_KERNEL_PATCH_MSG(L" Patched KiVerifyScopesExecute [RVA: 0x%X].\r\n",
(UINT32)(KiVerifyScopesExecute - ImageBase));
}
+ if (KiMcaDeferredRecoveryServiceCallers[0] != NULL && KiMcaDeferredRecoveryServiceCallers[1] != NULL)
+ {
+ PRINT_KERNEL_PATCH_MSG(L" Patched KiMcaDeferredRecoveryService [RVAs: 0x%X, 0x%X].\r\n",
+ (UINT32)(KiMcaDeferredRecoveryServiceCallers[0] - ImageBase),
+ (UINT32)(KiMcaDeferredRecoveryServiceCallers[1] - ImageBase));
+ }
if (KiSwInterruptPatternAddress != NULL)
{
PRINT_KERNEL_PATCH_MSG(L" Patched KiSwInterrupt [RVA: 0x%X].\r\n",