aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthijs Lavrijsen <mattiwatti@gmail.com>2023-03-26 15:22:09 +0200
committerMatthijs Lavrijsen <mattiwatti@gmail.com>2023-03-26 15:22:09 +0200
commit82b91beedf492b3725d987bfa2e5001f33686007 (patch)
treedaf4f0e68ba745ad95e72ea3d08f43fe0a88fe6e
parent4465715c2c3abbd554f2ee09360532bcf257d34a (diff)
EfiGuardDxe: clear and restore CR0.WP when copying
This is intended to deal with the UEFI memory protection protocol (EFI_MEMORY_ATTRIBUTE_PROTOCOL) introduced in the UEFI 2.10 specification.
-rw-r--r--EfiGuardDxe/EfiGuardDxe.h1
-rw-r--r--EfiGuardDxe/PatchBootmgr.c11
-rw-r--r--EfiGuardDxe/PatchNtoskrnl.c26
-rw-r--r--EfiGuardDxe/PatchWinload.c22
4 files changed, 38 insertions, 22 deletions
diff --git a/EfiGuardDxe/EfiGuardDxe.h b/EfiGuardDxe/EfiGuardDxe.h
index 0970d3b..249ed8c 100644
--- a/EfiGuardDxe/EfiGuardDxe.h
+++ b/EfiGuardDxe/EfiGuardDxe.h
@@ -49,6 +49,7 @@ extern BOOLEAN gEfiGoneVirtual;
// Universal template bytes for a faux call inline hook (mov [e|r]ax, <addr>, push [e|r]ax, ret)
//
extern CONST UINT8 gHookTemplate[(sizeof(VOID*) / 4) + sizeof(VOID*) + 2];
+extern CONST UINTN gHookTemplateAddressOffset;
//
diff --git a/EfiGuardDxe/PatchBootmgr.c b/EfiGuardDxe/PatchBootmgr.c
index 490d040..5730664 100644
--- a/EfiGuardDxe/PatchBootmgr.c
+++ b/EfiGuardDxe/PatchBootmgr.c
@@ -24,6 +24,11 @@ CONST UINT8 gHookTemplate[] =
0x50, // push [e|r]ax
0xC3 // ret
};
+#if defined(MDE_CPU_X64)
+CONST UINTN gHookTemplateAddressOffset = 2;
+#elif defined(MDE_CPU_IA32)
+CONST UINTN gHookTemplateAddressOffset = 1;
+#endif
// Signature for [bootmgfw|bootmgr]!ImgArch[Efi]StartBootApplication
@@ -49,7 +54,7 @@ HookedBootManagerImgArchStartBootApplication(
)
{
// Restore the original function bytes that we replaced with our hook
- CopyMem(OriginalFunction, OriginalFunctionBytes, sizeof(gHookTemplate));
+ CopyWpMem(OriginalFunction, OriginalFunctionBytes, sizeof(gHookTemplate));
// Clear the screen and paint it, paint it bl... green
CONST INT32 OriginalAttribute = SetConsoleTextColour(EFI_GREEN, TRUE);
@@ -325,8 +330,8 @@ PatchBootManager(
CopyMem(BackupAddress, (VOID*)OriginalAddress, sizeof(gHookTemplate));
// Place faux call (push addr, ret) at the start of the function to transfer execution to our hook
- CopyMem((VOID*)OriginalAddress, gHookTemplate, sizeof(gHookTemplate));
- *(UINTN*)((UINT8*)OriginalAddress + 2) = (UINTN)HookAddress;
+ CopyWpMem((VOID*)OriginalAddress, gHookTemplate, sizeof(gHookTemplate));
+ CopyWpMem((UINT8*)OriginalAddress + gHookTemplateAddressOffset, (UINTN*)&HookAddress, sizeof(UINTN));
gBS->RestoreTPL(Tpl);
diff --git a/EfiGuardDxe/PatchNtoskrnl.c b/EfiGuardDxe/PatchNtoskrnl.c
index 1604f7a..fad6914 100644
--- a/EfiGuardDxe/PatchNtoskrnl.c
+++ b/EfiGuardDxe/PatchNtoskrnl.c
@@ -384,19 +384,19 @@ DisablePatchGuard(
// We have all the addresses we need; now do the actual patching.
CONST UINT32 Yes = 0xC301B0; // mov al, 1, ret
CONST UINT32 No = 0xC3C033; // xor eax, eax, ret
- *((UINT32*)KeInitAmd64SpecificState) = No;
- *((UINT32*)CcInitializeBcbProfiler) = Yes;
+ CopyWpMem(KeInitAmd64SpecificState, &No, sizeof(No));
+ CopyWpMem(CcInitializeBcbProfiler, &Yes, sizeof(Yes));
if (ExpLicenseWatchInitWorker != NULL)
- *((UINT32*)ExpLicenseWatchInitWorker) = No;
+ CopyWpMem(ExpLicenseWatchInitWorker, &No, sizeof(No));
if (KiVerifyScopesExecute != NULL)
- *(UINT32*)KiVerifyScopesExecute = No;
+ CopyWpMem(KiVerifyScopesExecute, &No, sizeof(No));
if (KiMcaDeferredRecoveryServiceCallers[0] != NULL && KiMcaDeferredRecoveryServiceCallers[1] != NULL)
{
- *(UINT32*)KiMcaDeferredRecoveryServiceCallers[0] = No;
- *(UINT32*)KiMcaDeferredRecoveryServiceCallers[1] = No;
+ CopyWpMem(KiMcaDeferredRecoveryServiceCallers[0], &No, sizeof(No));
+ CopyWpMem(KiMcaDeferredRecoveryServiceCallers[1], &No, sizeof(No));
}
if (KiSwInterruptPatternAddress != NULL)
- SetMem(KiSwInterruptPatternAddress, sizeof(SigKiSwInterrupt), 0x90); // 11 x nop
+ SetWpMem(KiSwInterruptPatternAddress, sizeof(SigKiSwInterrupt), 0x90); // 11 x nop
// Print info
PRINT_KERNEL_PATCH_MSG(L"\r\n Patched KeInitAmd64SpecificState [RVA: 0x%X].\r\n",
@@ -704,14 +704,20 @@ DisableDSE(
// We have all the addresses we need; now do the actual patching.
// SepInitializeCodeIntegrity is only patched when using the 'nuke option' DSE_DISABLE_AT_BOOT.
if (BypassType == DSE_DISABLE_AT_BOOT)
- *((UINT16*)SepInitializeCodeIntegrityMovEcxAddress) = 0xC931; // xor ecx, ecx
+ {
+ CONST UINT16 ZeroEcx = 0xC931;
+ CopyWpMem(SepInitializeCodeIntegrityMovEcxAddress, &ZeroEcx, sizeof(ZeroEcx)); // xor ecx, ecx
+ }
// SeValidateImageData *must* be patched on Windows Vista and 7 regardless of the DSE bypass method.
// On Windows >= 8, again require DSE_DISABLE_AT_BOOT to do anything as it is otherwise harmless.
if (BuildNumber < 9200)
- *SeValidateImageDataJzAddress = 0xEB; // jmp
+ SetWpMem(SeValidateImageDataJzAddress, sizeof(UINT8), 0xEB); // jmp
else if (BypassType == DSE_DISABLE_AT_BOOT)
- *(UINT32*)(SeValidateImageDataMovEaxAddress + 1 /*skip existing mov opcode*/) = 0x0; // mov eax, 0
+ {
+ CONST UINT32 Zero = 0;
+ CopyWpMem(SeValidateImageDataMovEaxAddress + 1 /*skip existing mov*/, &Zero, sizeof(Zero)); // mov eax, 0
+ }
if (BuildNumber >= 16299 && BypassType == DSE_DISABLE_AT_BOOT)
{
diff --git a/EfiGuardDxe/PatchWinload.c b/EfiGuardDxe/PatchWinload.c
index edf15ad..baa28d7 100644
--- a/EfiGuardDxe/PatchWinload.c
+++ b/EfiGuardDxe/PatchWinload.c
@@ -128,7 +128,7 @@ HookedOslFwpKernelSetupPhase1(
)
{
// Restore the original function bytes that we replaced with our hook
- CopyMem((VOID*)gOriginalOslFwpKernelSetupPhase1, gOslFwpKernelSetupPhase1Backup, sizeof(gOslFwpKernelSetupPhase1Backup));
+ CopyWpMem((VOID*)gOriginalOslFwpKernelSetupPhase1, gOslFwpKernelSetupPhase1Backup, sizeof(gHookTemplate));
UINT8* LoadOrderListHeadAddress = (UINT8*)&LoaderBlock->LoadOrderListHead;
if (gKernelPatchInfo.BuildNumber < 7600)
@@ -238,7 +238,7 @@ PatchImgpValidateImageHash(
}
// Backtrack to function start
- CONST UINT8* ImgpValidateImageHash = BacktrackToFunctionStart(ImageBase, NtHeaders, AndMinusFortyOneAddress);
+ UINT8* ImgpValidateImageHash = BacktrackToFunctionStart(ImageBase, NtHeaders, AndMinusFortyOneAddress);
if (ImgpValidateImageHash == NULL)
{
Print(L" Failed to find %S!ImgpValidateImageHash%S.\r\n",
@@ -247,7 +247,8 @@ PatchImgpValidateImageHash(
}
// Apply the patch
- *((UINT32*)ImgpValidateImageHash) = 0xC3C033; // xor eax, eax, ret
+ CONST UINT32 Ok = 0xC3C033; // xor eax, eax, ret
+ CopyWpMem(ImgpValidateImageHash, &Ok, sizeof(Ok));
// Print info
Print(L" Patched %S!ImgpValidateImageHash [RVA: 0x%X].\r\n",
@@ -375,7 +376,7 @@ PatchImgpFilterValidationFailure(
}
// Backtrack to function start
- CONST UINT8* ImgpFilterValidationFailure = BacktrackToFunctionStart(ImageBase, NtHeaders, LeaIntegrityFailureAddress);
+ UINT8* ImgpFilterValidationFailure = BacktrackToFunctionStart(ImageBase, NtHeaders, LeaIntegrityFailureAddress);
if (ImgpFilterValidationFailure == NULL)
{
Print(L" Failed to find %S!ImgpFilterValidationFailure%S.\r\n",
@@ -384,7 +385,8 @@ PatchImgpFilterValidationFailure(
}
// Apply the patch
- *((UINT32*)ImgpFilterValidationFailure) = 0xC3C033; // xor eax, eax, ret
+ CONST UINT32 Ok = 0xC3C033; // xor eax, eax, ret
+ CopyWpMem(ImgpFilterValidationFailure, &Ok, sizeof(Ok));
// Print info
Print(L" Patched %S!ImgpFilterValidationFailure [RVA: 0x%X].\r\n\r\n",
@@ -679,16 +681,18 @@ PatchWinload(
goto Exit;
}
- Print(L"HookedOslFwpKernelSetupPhase1 at 0x%p.\r\n", (VOID*)&HookedOslFwpKernelSetupPhase1);
+ CONST UINTN HookedOslFwpKernelSetupPhase1Address = (UINTN)&HookedOslFwpKernelSetupPhase1;
+ Print(L"HookedOslFwpKernelSetupPhase1 at 0x%p.\r\n", (VOID*)HookedOslFwpKernelSetupPhase1Address);
CONST EFI_TPL Tpl = gBS->RaiseTPL(TPL_HIGH_LEVEL); // Note: implies cli
// Backup original function prologue
- CopyMem(gOslFwpKernelSetupPhase1Backup, (VOID*)gOriginalOslFwpKernelSetupPhase1, sizeof(gOslFwpKernelSetupPhase1Backup));
+ CopyMem(gOslFwpKernelSetupPhase1Backup, (VOID*)gOriginalOslFwpKernelSetupPhase1, sizeof(gHookTemplate));
// Place faux call (push addr, ret) at the start of the function to transfer execution to our hook
- CopyMem((VOID*)gOriginalOslFwpKernelSetupPhase1, gHookTemplate, sizeof(gHookTemplate));
- *(UINTN*)((UINT8*)gOriginalOslFwpKernelSetupPhase1 + 2) = (UINTN)&HookedOslFwpKernelSetupPhase1;
+ CopyWpMem((VOID*)gOriginalOslFwpKernelSetupPhase1, gHookTemplate, sizeof(gHookTemplate));
+ CopyWpMem((UINT8*)gOriginalOslFwpKernelSetupPhase1 + gHookTemplateAddressOffset,
+ (UINTN*)&HookedOslFwpKernelSetupPhase1Address, sizeof(HookedOslFwpKernelSetupPhase1Address));
gBS->RestoreTPL(Tpl);