diff options
Diffstat (limited to 'Application')
-rw-r--r-- | Application/EfiDSEFix/src/EfiDSEFix.cpp | 165 | ||||
-rw-r--r-- | Application/EfiDSEFix/src/EfiDSEFix.exe.manifest | 2 | ||||
-rw-r--r-- | Application/EfiDSEFix/src/EfiDSEFix.vcxproj | 10 | ||||
-rw-r--r-- | Application/EfiDSEFix/src/main.cpp | 68 | ||||
-rw-r--r-- | Application/EfiDSEFix/src/sysinfo.cpp | 6 | ||||
-rw-r--r-- | Application/Loader/Loader.c | 288 | ||||
-rw-r--r-- | Application/Loader/Loader.inf | 10 | ||||
-rw-r--r-- | Application/Loader/Loader.vcxproj | 4 |
8 files changed, 309 insertions, 244 deletions
diff --git a/Application/EfiDSEFix/src/EfiDSEFix.cpp b/Application/EfiDSEFix/src/EfiDSEFix.cpp index 924f759..03bfbba 100644 --- a/Application/EfiDSEFix/src/EfiDSEFix.cpp +++ b/Application/EfiDSEFix/src/EfiDSEFix.cpp @@ -31,11 +31,11 @@ FindKernelModule( for (ULONG i = 0; i < Modules->NumberOfModules; ++i) { - RTL_PROCESS_MODULE_INFORMATION Module = Modules->Modules[i]; - if (_stricmp(ModuleName, reinterpret_cast<PCHAR>(Module.FullPathName) + Module.OffsetToFileName) == 0) + const PRTL_PROCESS_MODULE_INFORMATION Module = &Modules->Modules[i]; + if (_stricmp(ModuleName, reinterpret_cast<PCHAR>(Module->FullPathName) + Module->OffsetToFileName) == 0) { - *ModuleBase = reinterpret_cast<ULONG_PTR>(Module.ImageBase); - Status = Module.ImageBase == nullptr ? STATUS_NOT_FOUND : STATUS_SUCCESS; + *ModuleBase = reinterpret_cast<ULONG_PTR>(Module->ImageBase); + Status = Module->ImageBase == nullptr ? STATUS_NOT_FOUND : STATUS_SUCCESS; break; } } @@ -48,7 +48,7 @@ Exit: // For Windows Vista/7. Credits: DSEFix by hfiref0x static LONG -QueryCiEnabled( +FindCiEnabled( _In_ PVOID MappedBase, _In_ SIZE_T SizeOfImage, _In_ ULONG_PTR KernelBase, @@ -73,7 +73,7 @@ QueryCiEnabled( // For Windows 8 and worse. Credits: DSEFix by hfiref0x static LONG -QueryCiOptions( +FindCiOptions( _In_ PVOID MappedBase, _In_ ULONG_PTR CiDllBase, _Out_ PULONG_PTR gCiOptionsAddress @@ -183,34 +183,8 @@ QueryCiOptions( } static -BOOLEAN -QueryVbsEnabled( - ) -{ - SYSTEM_CODEINTEGRITY_INFORMATION CodeIntegrityInfo = { sizeof(SYSTEM_CODEINTEGRITY_INFORMATION) }; - NTSTATUS Status = NtQuerySystemInformation(SystemCodeIntegrityInformation, - &CodeIntegrityInfo, - sizeof(CodeIntegrityInfo), - nullptr); - if (NT_SUCCESS(Status) && - (CodeIntegrityInfo.CodeIntegrityOptions & (CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED | CODEINTEGRITY_OPTION_HVCI_IUM_ENABLED)) != 0) - return TRUE; - - SYSTEM_ISOLATED_USER_MODE_INFORMATION IumInfo = { 0 }; - Status = NtQuerySystemInformation(SystemIsolatedUserModeInformation, - &IumInfo, - sizeof(IumInfo), - nullptr); - if (NT_SUCCESS(Status) && - (IumInfo.SecureKernelRunning || IumInfo.HvciEnabled)) - return TRUE; - - return FALSE; -} - -static NTSTATUS -AnalyzeCi( +FindCiOptionsVariable( _Out_ PVOID *CiOptionsAddress ) { @@ -243,7 +217,7 @@ AnalyzeCi( goto Exit; ULONG_PTR gCiOptionsAddress; - const LONG Relative = QueryCiOptions(MappedBase, CiDllBase, &gCiOptionsAddress); + const LONG Relative = FindCiOptions(MappedBase, CiDllBase, &gCiOptionsAddress); if (Relative != 0) { *CiOptionsAddress = reinterpret_cast<PVOID>(gCiOptionsAddress); @@ -263,7 +237,7 @@ AnalyzeCi( goto Exit; ULONG_PTR gCiEnabledAddress; - const LONG Relative = QueryCiEnabled(MappedBase, ViewSize, KernelBase, &gCiEnabledAddress); + const LONG Relative = FindCiEnabled(MappedBase, ViewSize, KernelBase, &gCiEnabledAddress); if (Relative != 0) { *CiOptionsAddress = reinterpret_cast<PVOID>(gCiEnabledAddress); @@ -281,47 +255,29 @@ Exit: } static -NTSTATUS -SetSystemEnvironmentPrivilege( - _In_ BOOLEAN Enable, - _Out_opt_ PBOOLEAN WasEnabled - ) -{ - if (WasEnabled != nullptr) - *WasEnabled = FALSE; - - BOOLEAN SeSystemEnvironmentWasEnabled; - const NTSTATUS Status = RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, - Enable, - FALSE, - &SeSystemEnvironmentWasEnabled); - - if (NT_SUCCESS(Status) && WasEnabled != nullptr) - *WasEnabled = SeSystemEnvironmentWasEnabled; - - return Status; -} - -static -NTSTATUS -SetDebugPrivilege( - _In_ BOOLEAN Enable, - _Out_opt_ PBOOLEAN WasEnabled +BOOLEAN +IsVbsEnabled( ) { - if (WasEnabled != nullptr) - *WasEnabled = FALSE; - - BOOLEAN SeDebugWasEnabled; - const NTSTATUS Status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, - Enable, - FALSE, - &SeDebugWasEnabled); + SYSTEM_CODEINTEGRITY_INFORMATION CodeIntegrityInfo = { sizeof(SYSTEM_CODEINTEGRITY_INFORMATION) }; + NTSTATUS Status = NtQuerySystemInformation(SystemCodeIntegrityInformation, + &CodeIntegrityInfo, + sizeof(CodeIntegrityInfo), + nullptr); + if (NT_SUCCESS(Status) && + (CodeIntegrityInfo.CodeIntegrityOptions & (CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED | CODEINTEGRITY_OPTION_HVCI_IUM_ENABLED)) != 0) + return TRUE; - if (NT_SUCCESS(Status) && WasEnabled != nullptr) - *WasEnabled = SeDebugWasEnabled; + SYSTEM_ISOLATED_USER_MODE_INFORMATION IumInfo = { 0 }; + Status = NtQuerySystemInformation(SystemIsolatedUserModeInformation, + &IumInfo, + sizeof(IumInfo), + nullptr); + if (NT_SUCCESS(Status) && + (IumInfo.SecureKernelRunning || IumInfo.HvciEnabled)) + return TRUE; - return Status; + return FALSE; } NTSTATUS @@ -330,24 +286,9 @@ TestSetVariableHook( { UINT16 Mz; - // Enable privileges in case we were called directly from the CLI with --check - BOOLEAN SeSystemEnvironmentWasEnabled, SeDebugWasEnabled; - NTSTATUS Status = SetSystemEnvironmentPrivilege(TRUE, &SeSystemEnvironmentWasEnabled); - if (!NT_SUCCESS(Status)) + if (IsVbsEnabled()) { - Printf(L"Fatal error: failed to acquire SE_SYSTEM_ENVIRONMENT_PRIVILEGE. Make sure you are running as administrator.\n"); - return Status; - } - Status = SetDebugPrivilege(TRUE, &SeDebugWasEnabled); - if (!NT_SUCCESS(Status)) - { - Printf(L"Fatal error: failed to acquire SE_DEBUG_PRIVILEGE. Make sure you are running as administrator.\n"); - return Status; - } - - if (QueryVbsEnabled()) - { - Printf(L"Fatal error: VBS (Virtualization Based Security) is enabled and running on this system.\n" + Printf(L"Error: VBS (Virtualization Based Security) is enabled and running on this system.\n" "Attempting to read or write to or from kernel space using EFI runtime services will result in a bugcheck.\n" "Either the EfiGuard DXE driver is not loaded, or it failed to disable VBS during boot.\n" "Not continuing.\n"); @@ -356,19 +297,18 @@ TestSetVariableHook( // Find some kernel address to read ULONG_PTR HalBase; - Status = FindKernelModule("hal.dll", &HalBase); + NTSTATUS Status = FindKernelModule("hal.dll", &HalBase); if (!NT_SUCCESS(Status)) return Status; - // Set up the struct for a backdoor kernel mode read. See TriggerExploit for explanations + // Set up the struct for a backdoor kernel mode read. See WriteToCiOptions for explanations EFIGUARD_BACKDOOR_DATA BackdoorData; RtlZeroMemory(&BackdoorData, sizeof(BackdoorData)); BackdoorData.CookieValue = EFIGUARD_BACKDOOR_COOKIE_VALUE; BackdoorData.KernelAddress = reinterpret_cast<PVOID>(HalBase); BackdoorData.u.Qword = UINT64_MAX; // Bogus value to verify write-back after the read operation - BackdoorData.IsMemCopy = FALSE; - BackdoorData.IsReadOperation = TRUE; BackdoorData.Size = sizeof(UINT16); + BackdoorData.ReadOnly = TRUE; // Call SetVariable() UNICODE_STRING VariableName = RTL_CONSTANT_STRING(EFIGUARD_BACKDOOR_VARIABLE_NAME); @@ -397,7 +337,7 @@ TestSetVariableHook( if (!NT_SUCCESS(Status)) { Printf(L"The EfiGuard DXE driver is either not loaded in SETVARIABLE_HOOK mode, or it is malfunctioning.\n"); - goto Exit; + return Status; } // Check if hal.dll still starts with "MZ" @@ -409,16 +349,12 @@ TestSetVariableHook( Status = STATUS_INVALID_IMAGE_NOT_MZ; // Literally } -Exit: - SetSystemEnvironmentPrivilege(SeSystemEnvironmentWasEnabled, nullptr); - SetDebugPrivilege(SeDebugWasEnabled, nullptr); - return Status; } static NTSTATUS -TriggerExploit( +WriteToCiOptions( _In_ PVOID CiVariableAddress, _In_ ULONG CiOptionsValue, _Out_opt_ PULONG OldCiOptionsValue, @@ -447,9 +383,8 @@ TriggerExploit( BackdoorData.u.s.Dword = static_cast<UINT32>(CiOptionsValue); else if (CiPatchSize == sizeof(UINT8)) BackdoorData.u.s.Byte = static_cast<UINT8>(CiOptionsValue); - BackdoorData.IsMemCopy = FALSE; // This is a scalar operation, not memcpy - BackdoorData.IsReadOperation = ReadOnly; // Specify whether this is a read or a write operation - BackdoorData.Size = CiPatchSize; // This value determines the field (Byte/Word/Dword/Qword) that the value to write will be read from, and written to on return + BackdoorData.Size = CiPatchSize; // Determines which field the value will be read/written from/to + BackdoorData.ReadOnly = ReadOnly; // Whether this is a read or read + write // Call NtSetSystemEnvironmentValueEx -> [...] -> hal!HalSetEnvironmentVariableEx -> hal!HalEfiSetEnvironmentVariable -> EfiRT->SetVariable. // On Windows >= 8 it is possible to use SetFirmwareEnvironmentVariableExW. We use the syscall directly because it exists on Windows 7 and Vista. @@ -475,6 +410,8 @@ TriggerExploit( *OldCiOptionsValue = OldCiOptions; } + RtlZeroMemory(&BackdoorData, sizeof(BackdoorData)); + return STATUS_SUCCESS; } @@ -488,38 +425,18 @@ AdjustCiOptions( if (OldCiOptionsValue != nullptr) *OldCiOptionsValue = CODEINTEGRITY_OPTION_ENABLED; - // Enable privileges - BOOLEAN SeSystemEnvironmentWasEnabled, SeDebugWasEnabled; - NTSTATUS Status = SetSystemEnvironmentPrivilege(TRUE, &SeSystemEnvironmentWasEnabled); - if (!NT_SUCCESS(Status)) - { - Printf(L"Fatal error: failed to acquire SE_SYSTEM_ENVIRONMENT_PRIVILEGE. Make sure you are running as administrator.\n"); - return Status; - } - Status = SetDebugPrivilege(TRUE, &SeDebugWasEnabled); - if (!NT_SUCCESS(Status)) - { - Printf(L"Fatal error: failed to acquire SE_DEBUG_PRIVILEGE. Make sure you are running as administrator.\n"); - return Status; - } - // Find CI!g_CiOptions/nt!g_CiEnabled PVOID CiOptionsAddress; - Status = AnalyzeCi(&CiOptionsAddress); + NTSTATUS Status = FindCiOptionsVariable(&CiOptionsAddress); if (!NT_SUCCESS(Status)) return Status; Printf(L"%ls at 0x%p.\n", (NtCurrentPeb()->OSBuildNumber >= 9200 ? L"CI!g_CiOptions" : L"nt!g_CiEnabled"), CiOptionsAddress); // Enable/disable CI - Status = TriggerExploit(CiOptionsAddress, + Status = WriteToCiOptions(CiOptionsAddress, CiOptionsValue, OldCiOptionsValue, ReadOnly); - - // Revert privileges - SetSystemEnvironmentPrivilege(SeSystemEnvironmentWasEnabled, nullptr); - SetDebugPrivilege(SeDebugWasEnabled, nullptr); - return Status; } diff --git a/Application/EfiDSEFix/src/EfiDSEFix.exe.manifest b/Application/EfiDSEFix/src/EfiDSEFix.exe.manifest index af2f7de..16afbf5 100644 --- a/Application/EfiDSEFix/src/EfiDSEFix.exe.manifest +++ b/Application/EfiDSEFix/src/EfiDSEFix.exe.manifest @@ -3,7 +3,7 @@ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> - <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> + <requestedExecutionLevel level="asInvoker" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> diff --git a/Application/EfiDSEFix/src/EfiDSEFix.vcxproj b/Application/EfiDSEFix/src/EfiDSEFix.vcxproj index 44675b5..c588f60 100644 --- a/Application/EfiDSEFix/src/EfiDSEFix.vcxproj +++ b/Application/EfiDSEFix/src/EfiDSEFix.vcxproj @@ -26,6 +26,8 @@ <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v143</PlatformToolset> <SpectreMitigation>false</SpectreMitigation> + <VcpkgEnabled>false</VcpkgEnabled> + <EnableStdModules>false</EnableStdModules> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release (native subsystem)|x64'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> @@ -34,6 +36,8 @@ <CharacterSet>Unicode</CharacterSet> <PlatformToolset>v143</PlatformToolset> <SpectreMitigation>false</SpectreMitigation> + <VcpkgEnabled>false</VcpkgEnabled> + <EnableStdModules>false</EnableStdModules> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> @@ -62,7 +66,7 @@ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <RuntimeTypeInfo>false</RuntimeTypeInfo> <LanguageStandard>stdcpplatest</LanguageStandard> - <AdditionalOptions>/Gw /utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions>/Gw /utf-8 /Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> <BufferSecurityCheck>false</BufferSecurityCheck> <DisableSpecificWarnings>4201</DisableSpecificWarnings> <ExceptionHandling>false</ExceptionHandling> @@ -71,6 +75,7 @@ <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)../MdePkg/Include;$(SolutionDir)../MdePkg/Include/X64;$(SolutionDir)../MdeModulePkg/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <IntrinsicFunctions>true</IntrinsicFunctions> <BuildStlModules>false</BuildStlModules> + <EnableModules>false</EnableModules> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -101,7 +106,7 @@ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <RuntimeTypeInfo>false</RuntimeTypeInfo> <LanguageStandard>stdcpplatest</LanguageStandard> - <AdditionalOptions>/Gw /utf-8 %(AdditionalOptions)</AdditionalOptions> + <AdditionalOptions>/Gw /utf-8 /Zc:threadSafeInit- %(AdditionalOptions)</AdditionalOptions> <BufferSecurityCheck>false</BufferSecurityCheck> <DisableSpecificWarnings>4201</DisableSpecificWarnings> <ExceptionHandling>false</ExceptionHandling> @@ -110,6 +115,7 @@ <AdditionalIncludeDirectories>$(SolutionDir)Include;$(SolutionDir)../MdePkg/Include;$(SolutionDir)../MdePkg/Include/X64;$(SolutionDir)../MdeModulePkg/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <IntrinsicFunctions>true</IntrinsicFunctions> <BuildStlModules>false</BuildStlModules> + <EnableModules>false</EnableModules> </ClCompile> <Link> <SubSystem>Native</SubSystem> diff --git a/Application/EfiDSEFix/src/main.cpp b/Application/EfiDSEFix/src/main.cpp index 50e336a..8cd8cb9 100644 --- a/Application/EfiDSEFix/src/main.cpp +++ b/Application/EfiDSEFix/src/main.cpp @@ -9,13 +9,13 @@ PrintUsage( { const BOOLEAN Win8OrHigher = (RtlNtMajorVersion() >= 6 && RtlNtMinorVersion() >= 2) || RtlNtMajorVersion() > 6; const PCWCHAR CiOptionsName = Win8OrHigher ? L"g_CiOptions" : L"g_CiEnabled"; - Printf(L"\nUsage: %ls [COMMAND]\n\n" - L"Commands:\n\n" - L"-c, --check%17lsTest backdoor hook\n" - L"-r, --read%18lsRead current %ls value\n" - L"-d, --disable%15lsDisable DSE\n" - L"-e, --enable%ls%2ls(Re)enable DSE\n" - L"-i, --info%18lsDump system info\n", + Printf(L"\nUsage: %ls <COMMAND>\n\n" + L"Commands:\n" + L" -c, --check%17lsTest EFI SetVariable hook\n" + L" -r, --read%18lsRead current %ls value\n" + L" -d, --disable%15lsDisable DSE\n" + L" -e, --enable%ls%2ls(Re)enable DSE\n" + L" -i, --info%18lsDump system info\n", ProgramName, L"", L"", CiOptionsName, L"", (Win8OrHigher ? L" [g_CiOptions]" : L" "), @@ -26,14 +26,31 @@ int wmain(int argc, wchar_t** argv) { NT_ASSERT(argc != 0); - if (argc == 1 || argc > 3 || - (argc == 3 && wcstoul(argv[2], nullptr, 16) == 0)) + if (argc <= 1 || argc > 3 || + (argc == 3 && wcstoul(argv[2], nullptr, 16) == 0) || + wcsncmp(argv[1], L"-h", sizeof(L"-h") / sizeof(WCHAR) - 1) == 0 || + wcsncmp(argv[1], L"--help", sizeof(L"--help") / sizeof(WCHAR) - 1) == 0) { // Print help text PrintUsage(argv[0]); return 0; } + // All remaining commands require admin privileges + BOOLEAN SeSystemEnvironmentWasEnabled, SeDebugWasEnabled; + NTSTATUS Status = RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, TRUE, FALSE, &SeSystemEnvironmentWasEnabled); + if (!NT_SUCCESS(Status)) + { + Printf(L"Error: failed to acquire SE_SYSTEM_ENVIRONMENT_PRIVILEGE.\n%ls must be run as Administrator.\n", argv[0]); + return Status; + } + Status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &SeDebugWasEnabled); + if (!NT_SUCCESS(Status)) + { + Printf(L"Error: failed to acquire SE_DEBUG_PRIVILEGE.\n%ls must be run as Administrator.\n", argv[0]); + return Status; + } + // Parse command line params const BOOLEAN Win8OrHigher = (RtlNtMajorVersion() >= 6 && RtlNtMinorVersion() >= 2) || RtlNtMajorVersion() > 6; const ULONG EnabledCiOptionsValue = Win8OrHigher ? 0x6 : CODEINTEGRITY_OPTION_ENABLED; @@ -41,15 +58,6 @@ int wmain(int argc, wchar_t** argv) ULONG CiOptionsValue; BOOLEAN ReadOnly = FALSE; - if (wcsncmp(argv[1], L"-c", sizeof(L"-c") / sizeof(WCHAR) - 1) == 0 || - wcsncmp(argv[1], L"--check", sizeof(L"--check") / sizeof(WCHAR) - 1) == 0) - { - Printf(L"Checking for working EFI SetVariable() backdoor...\n"); - const NTSTATUS Status = TestSetVariableHook(); - if (NT_SUCCESS(Status)) // Any errors have already been printed - Printf(L"Success!\n"); - return Status; - } if (wcsncmp(argv[1], L"-r", sizeof(L"-r") / sizeof(WCHAR) - 1) == 0 || wcsncmp(argv[1], L"--read", sizeof(L"--read") / sizeof(WCHAR) - 1) == 0) { @@ -77,20 +85,31 @@ int wmain(int argc, wchar_t** argv) Printf(L"(Re)enabling DSE...\n"); } } + else if (wcsncmp(argv[1], L"-c", sizeof(L"-c") / sizeof(WCHAR) - 1) == 0 || + wcsncmp(argv[1], L"--check", sizeof(L"--check") / sizeof(WCHAR) - 1) == 0) + { + Printf(L"Checking for working EFI SetVariable hook...\n"); + Status = TestSetVariableHook(); + if (NT_SUCCESS(Status)) // Any errors have already been printed + Printf(L"Success.\n"); + goto Exit; + } else if (wcsncmp(argv[1], L"-i", sizeof(L"-i") / sizeof(WCHAR) - 1) == 0 || wcsncmp(argv[1], L"--info", sizeof(L"--info") / sizeof(WCHAR) - 1) == 0) { - return DumpSystemInformation(); + Status = DumpSystemInformation(); + goto Exit; } else { PrintUsage(argv[0]); - return STATUS_INVALID_PARAMETER; + Status = STATUS_INVALID_PARAMETER; + goto Exit; } - // Trigger EFI driver exploit and write new value to g_CiOptions/g_CiEnabled + // Call EFI runtime SetVariable service and write new value to g_CiOptions/g_CiEnabled ULONG OldCiOptionsValue; - const NTSTATUS Status = AdjustCiOptions(CiOptionsValue, &OldCiOptionsValue, ReadOnly); + Status = AdjustCiOptions(CiOptionsValue, &OldCiOptionsValue, ReadOnly); // Print result if (!NT_SUCCESS(Status)) @@ -105,6 +124,11 @@ int wmain(int argc, wchar_t** argv) Printf(L"Successfully %ls DSE. Original", CiOptionsValue == 0 ? L"disabled" : L"(re)enabled"); Printf(L" %ls value: 0x%lX\n", CiOptionsName, OldCiOptionsValue); } + +Exit: + RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, SeSystemEnvironmentWasEnabled, FALSE, &SeSystemEnvironmentWasEnabled); + RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, SeDebugWasEnabled, FALSE, &SeDebugWasEnabled); + return Status; } diff --git a/Application/EfiDSEFix/src/sysinfo.cpp b/Application/EfiDSEFix/src/sysinfo.cpp index 6b236e4..a0ad289 100644 --- a/Application/EfiDSEFix/src/sysinfo.cpp +++ b/Application/EfiDSEFix/src/sysinfo.cpp @@ -75,10 +75,10 @@ DumpSystemInformation( Printf(L"SystemModuleInformation: %08lX\n\n", Status); else { - const RTL_PROCESS_MODULE_INFORMATION Ntoskrnl = ModuleInfo->Modules[0]; + const PRTL_PROCESS_MODULE_INFORMATION Ntoskrnl = &ModuleInfo->Modules[0]; Printf(L"SystemModuleInformation:\n\t- Kernel: %S (%S)\n\n", - reinterpret_cast<PCCH>(Ntoskrnl.FullPathName + Ntoskrnl.OffsetToFileName), - reinterpret_cast<PCCH>(Ntoskrnl.FullPathName)); + reinterpret_cast<PCCH>(Ntoskrnl->FullPathName + Ntoskrnl->OffsetToFileName), + reinterpret_cast<PCCH>(Ntoskrnl->FullPathName)); } RtlFreeHeap(RtlProcessHeap(), 0, ModuleInfo); } diff --git a/Application/Loader/Loader.c b/Application/Loader/Loader.c index 665b2fe..aab4a5c 100644 --- a/Application/Loader/Loader.c +++ b/Application/Loader/Loader.c @@ -5,9 +5,11 @@ #include <Protocol/SimpleFileSystem.h> #include <Protocol/LoadedImage.h> #include <Protocol/LegacyBios.h> +#include <Library/PcdLib.h> #include <Library/UefiLib.h> #include <Library/DebugLib.h> #include <Library/MemoryAllocationLib.h> +#include <Library/ReportStatusCodeLib.h> #include <Library/DevicePathLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiBootManagerLib.h> @@ -15,16 +17,6 @@ // -// Define whether the loader should prompt for driver configuration or not. -// If this is 0, the defaults are used and Windows will be booted with no user interaction. -// This can be overridden on the command line with -D CONFIGURE_DRIVER=[0|1] -// -#ifndef CONFIGURE_DRIVER -#define CONFIGURE_DRIVER 0 -#endif - - -// // Paths to the driver to try // #ifndef EFIGUARD_DRIVER_FILENAME @@ -36,6 +28,13 @@ STATIC CHAR16* mDriverPaths[] = { L"\\" EFIGUARD_DRIVER_FILENAME }; +STATIC EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *mTextInputEx = NULL; + +VOID +EFIAPI +BmRepairAllControllers( + IN UINTN ReconnectRepairCount + ); VOID EFIAPI @@ -43,23 +42,65 @@ BmSetMemoryTypeInformationVariable( IN BOOLEAN Boot ); +BOOLEAN +EFIAPI +BmIsAutoCreateBootOption( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ); STATIC -BOOLEAN +VOID +ResetTextInput( + VOID + ) +{ + if (mTextInputEx != NULL) + mTextInputEx->Reset(mTextInputEx, FALSE); + else + gST->ConIn->Reset(gST->ConIn, FALSE); +} + +STATIC +UINT16 EFIAPI WaitForKey( VOID ) { - EFI_INPUT_KEY Key = { 0, 0 }; + EFI_KEY_DATA KeyData = { 0 }; UINTN Index = 0; - gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); - gST->ConIn->ReadKeyStroke(gST->ConIn, &Key); - - return Key.ScanCode != SCAN_ESC; + if (mTextInputEx != NULL) + { + gBS->WaitForEvent(1, &mTextInputEx->WaitForKeyEx, &Index); + mTextInputEx->ReadKeyStrokeEx(mTextInputEx, &KeyData); + } + else + { + gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); + gST->ConIn->ReadKeyStroke(gST->ConIn, &KeyData.Key); + } + return KeyData.Key.ScanCode; } -#if CONFIGURE_DRIVER +STATIC +UINT16 +EFIAPI +WaitForKeyWithTimeout( + IN UINTN Milliseconds + ) +{ + ResetTextInput(); + gBS->Stall(Milliseconds * 1000); + + EFI_KEY_DATA KeyData = { 0 }; + if (mTextInputEx != NULL) + mTextInputEx->ReadKeyStrokeEx(mTextInputEx, &KeyData); + else + gST->ConIn->ReadKeyStroke(gST->ConIn, &KeyData.Key); + + ResetTextInput(); + return KeyData.Key.ScanCode; +} STATIC UINT16 @@ -76,12 +117,20 @@ PromptInput( { SelectedChar = CHAR_NULL; - EFI_INPUT_KEY Key = { 0, 0 }; + EFI_KEY_DATA KeyData = { 0 }; UINTN Index = 0; - gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); - gST->ConIn->ReadKeyStroke(gST->ConIn, &Key); + if (mTextInputEx != NULL) + { + gBS->WaitForEvent(1, &mTextInputEx->WaitForKeyEx, &Index); + mTextInputEx->ReadKeyStrokeEx(mTextInputEx, &KeyData); + } + else + { + gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index); + gST->ConIn->ReadKeyStroke(gST->ConIn, &KeyData.Key); + } - if (Key.UnicodeChar == CHAR_LINEFEED || Key.UnicodeChar == CHAR_CARRIAGE_RETURN) + if (KeyData.Key.UnicodeChar == CHAR_LINEFEED || KeyData.Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { SelectedChar = DefaultSelection; break; @@ -89,9 +138,9 @@ PromptInput( for (UINTN i = 0; i < NumAcceptedChars; ++i) { - if (Key.UnicodeChar == AcceptedChars[i]) + if (KeyData.Key.UnicodeChar == AcceptedChars[i]) { - SelectedChar = Key.UnicodeChar; + SelectedChar = KeyData.Key.UnicodeChar; break; } } @@ -104,8 +153,43 @@ PromptInput( return SelectedChar; } -#endif +STATIC +CONST CHAR16* +EFIAPI +StriStr( + IN CONST CHAR16 *String1, + IN CONST CHAR16 *String2 + ) +{ + if (*String2 == L'\0') + return String1; + + while (*String1 != L'\0') + { + CONST CHAR16* FirstMatch = String1; + CONST CHAR16* String2Ptr = String2; + CHAR16 String1Char = CharToUpper(*String1); + CHAR16 String2Char = CharToUpper(*String2Ptr); + + while (String1Char == String2Char && String1Char != L'\0') + { + String1++; + String2Ptr++; + + String1Char = CharToUpper(*String1); + String2Char = CharToUpper(*String2Ptr); + } + + if (String2Char == L'\0') + return FirstMatch; + if (String1Char == L'\0') + return NULL; + + String1 = FirstMatch + 1; + } + return NULL; +} // // Try to find a file by browsing each device @@ -156,7 +240,8 @@ LocateFile( EFI_FILE_READ_ONLY); if (!EFI_ERROR(Status)) { - VolumeHandle->Close(FileHandle); + FileHandle->Close(FileHandle); + VolumeHandle->Close(VolumeHandle); *DevicePath = FileDevicePath(Handles[i], ImagePath); CHAR16 *PathString = ConvertDevicePathToText(*DevicePath, TRUE, TRUE); DEBUG((DEBUG_INFO, "[LOADER] Found file at %S.\r\n", PathString)); @@ -164,9 +249,10 @@ LocateFile( FreePool(PathString); break; } + VolumeHandle->Close(VolumeHandle); } - FreePool(Handles); + FreePool((VOID*)Handles); return Status; } @@ -219,9 +305,8 @@ SetHighestAvailableTextMode( STATIC EFI_STATUS EFIAPI -StartAndConfigureDriver( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE* SystemTable +StartEfiGuard( + IN BOOLEAN InteractiveConfiguration ) { EFIGUARD_DRIVER_PROTOCOL* EfiGuardDriverProtocol; @@ -251,7 +336,7 @@ StartAndConfigureDriver( EFI_HANDLE DriverHandle = NULL; Status = gBS->LoadImage(FALSE, // Request is not from boot manager - ImageHandle, + gImageHandle, DriverDevicePath, NULL, 0, @@ -268,58 +353,65 @@ StartAndConfigureDriver( Print(L"[LOADER] StartImage failed: %llx (%r).\r\n", Status, Status); goto Exit; } - - Status = gBS->LocateProtocol(&gEfiGuardDriverProtocolGuid, - NULL, - (VOID**)&EfiGuardDriverProtocol); - if (EFI_ERROR(Status)) - { - Print(L"[LOADER] LocateProtocol failed: %llx (%r).\r\n", Status, Status); - goto Exit; - } } else { + ASSERT_EFI_ERROR(Status); Print(L"[LOADER] The driver is already loaded.\r\n"); - Status = EFI_ALREADY_STARTED; + } + + Status = gBS->LocateProtocol(&gEfiGuardDriverProtocolGuid, + NULL, + (VOID**)&EfiGuardDriverProtocol); + if (EFI_ERROR(Status)) + { + Print(L"[LOADER] LocateProtocol failed: %llx (%r).\r\n", Status, Status); goto Exit; } -#if CONFIGURE_DRIVER - // - // Interactive driver configuration - // - Print(L"\r\nChoose the type of DSE bypass to use, or press ENTER for default:\r\n" - L" [1] No DSE bypass\r\n [2] Boot time DSE bypass\r\n [3] Runtime SetVariable hook (default)\r\n "); - CONST UINT16 AcceptedDseBypasses[] = { L'1', L'2', L'3' }; - CONST UINT16 SelectedDseBypass = PromptInput(AcceptedDseBypasses, - sizeof(AcceptedDseBypasses) / sizeof(UINT16), - L'3'); - - Print(L"Wait for a keypress to continue after each patch stage? (for debugging)\n" - L" [1] Yes\r\n [2] No (default)\r\n "); - CONST UINT16 YesNo[] = { L'1', L'2' }; - CONST UINT16 SelectedWaitForKeyPress = PromptInput(YesNo, - sizeof(YesNo) / sizeof(UINT16), - L'2'); - - EFIGUARD_CONFIGURATION_DATA ConfigData; - if (SelectedDseBypass == L'1') - ConfigData.DseBypassMethod = DSE_DISABLE_NONE; - else if (SelectedDseBypass == L'2') - ConfigData.DseBypassMethod = DSE_DISABLE_AT_BOOT; - else - ConfigData.DseBypassMethod = DSE_DISABLE_SETVARIABLE_HOOK; - ConfigData.WaitForKeyPress = (BOOLEAN)(SelectedWaitForKeyPress == L'1'); + if (InteractiveConfiguration) + { + // + // Interactive driver configuration + // + Print(L"\r\nChoose the type of DSE bypass to use, or press ENTER for default:\r\n" + L" [1] Runtime SetVariable hook (default)\r\n [2] Boot time DSE bypass\r\n [3] No DSE bypass\r\n "); + CONST UINT16 AcceptedDseBypasses[] = { L'1', L'2', L'3' }; + CONST UINT16 SelectedDseBypass = PromptInput(AcceptedDseBypasses, + sizeof(AcceptedDseBypasses) / sizeof(UINT16), + L'1'); + + Print(L"Wait for a keypress to continue after each patch stage?\n" + L" [1] No (default)\r\n [2] Yes (for debugging)\r\n "); + CONST UINT16 NoYes[] = { L'1', L'2' }; + CONST UINT16 SelectedWaitForKeyPress = PromptInput(NoYes, + sizeof(NoYes) / sizeof(UINT16), + L'1'); + + EFIGUARD_CONFIGURATION_DATA ConfigData; + switch (SelectedDseBypass) + { + case L'1': + default: + ConfigData.DseBypassMethod = DSE_DISABLE_SETVARIABLE_HOOK; + break; + case L'2': + ConfigData.DseBypassMethod = DSE_DISABLE_AT_BOOT; + break; + case L'3': + ConfigData.DseBypassMethod = DSE_DISABLE_NONE; + break; + } + ConfigData.WaitForKeyPress = (BOOLEAN)(SelectedWaitForKeyPress == L'2'); - // - // Send the configuration data to the driver - // - Status = EfiGuardDriverProtocol->Configure(&ConfigData); + // + // Send the configuration data to the driver + // + Status = EfiGuardDriverProtocol->Configure(&ConfigData); - if (EFI_ERROR(Status)) - Print(L"[LOADER] Driver Configure() returned error %llx (%r).\r\n", Status, Status); -#endif + if (EFI_ERROR(Status)) + Print(L"[LOADER] Driver Configure() returned error %llx (%r).\r\n", Status, Status); + } Exit: if (DriverDevicePath != NULL) @@ -406,8 +498,7 @@ TryBootOptionsInOrder( // but for some types of boots the filename will always be bootx64.efi, so this can't be avoided. if (!MaybeWindows && ConvertedPath != NULL && - (StrStr(ConvertedPath, L"bootmgfw.efi") != NULL || StrStr(ConvertedPath, L"BOOTMGFW.EFI") != NULL || - StrStr(ConvertedPath, L"bootx64.efi") != NULL || StrStr(ConvertedPath, L"BOOTX64.EFI") != NULL)) + (StriStr(ConvertedPath, L"bootmgfw.efi") != NULL || StriStr(ConvertedPath, L"bootx64.efi") != NULL)) { MaybeWindows = TRUE; } @@ -426,7 +517,9 @@ TryBootOptionsInOrder( // Print what we're booting if (ConvertedPath != NULL) { - Print(L"Booting %Sdevice path %S...\r\n", IsLegacy ? L"legacy " : L"", ConvertedPath); + Print(L"Booting \"%S\"...\r\n -> %S = %S\r\n", + (BootOptions[Index].Description != NULL ? BootOptions[Index].Description : L"<null description>"), + IsLegacy ? L"Legacy path" : L"Path", ConvertedPath); FreePool(ConvertedPath); } @@ -449,6 +542,13 @@ TryBootOptionsInOrder( // Signal the EVT_SIGNAL_READY_TO_BOOT event EfiSignalEventReadyToBoot(); + REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT)); + + // Repair system through DriverHealth protocol + BmRepairAllControllers(0); + + // Save the memory map in the MemoryTypeInformation variable for resuming from ACPI S4 (hibernate) + BmSetMemoryTypeInformationVariable((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT); // Handle BBS entries if (IsLegacy) @@ -470,18 +570,12 @@ TryBootOptionsInOrder( return !EFI_ERROR(BootOptions[Index].Status); } - // So again, DO NOT call this abortion: - //BmSetMemoryTypeInformationVariable((BOOLEAN)((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)); - // - // OK, maybe call it after all, but pretend this is *not* a boot entry, so that the system will not go into an infinite boot (reset) loop. - // This may or may not fix hibernation related issues (S4 entry/resume). See https://github.com/Mattiwatti/EfiGuard/issues/12 - BmSetMemoryTypeInformationVariable(FALSE); - // Ensure the image path is connected end-to-end by Dispatch()ing any required drivers through DXE services EfiBootManagerConnectDevicePath(BootOptions[Index].FilePath, NULL); // Instead of creating a ramdisk and reading the file into it (¿que?), just pass the path we saved earlier. // This is the point where the driver kicks in via its LoadImage hook. + REPORT_STATUS_CODE(EFI_PROGRESS_CODE, PcdGet32(PcdProgressCodeOsLoaderLoad)); EFI_HANDLE ImageHandle = NULL; Status = gBS->LoadImage(TRUE, gImageHandle, @@ -500,6 +594,7 @@ TryBootOptionsInOrder( gBS->UnloadImage(ImageHandle); Print(L"LoadImage error %llx (%r)\r\n", Status, Status); + BootOptions[Index].Status = Status; continue; } @@ -514,8 +609,11 @@ TryBootOptionsInOrder( ASSERT_EFI_ERROR(Status); // Set image load options from the boot option - ImageInfo->LoadOptionsSize = BootOptions[Index].OptionalDataSize; - ImageInfo->LoadOptions = BootOptions[Index].OptionalData; + if (!BmIsAutoCreateBootOption(&BootOptions[Index])) + { + ImageInfo->LoadOptionsSize = BootOptions[Index].OptionalDataSize; + ImageInfo->LoadOptions = BootOptions[Index].OptionalData; + } // "Clean to NULL because the image is loaded directly from the firmware's boot manager." (EDK2) Good call, I agree ImageInfo->ParentHandle = NULL; @@ -524,6 +622,7 @@ TryBootOptionsInOrder( gBS->SetWatchdogTimer((UINTN)(5 * 60), 0x0000, 0x00, NULL); // Start the image and set the return code in the boot option status + REPORT_STATUS_CODE(EFI_PROGRESS_CODE, PcdGet32(PcdProgressCodeOsLoaderStart)); Status = gBS->StartImage(ImageHandle, &BootOptions[Index].ExitDataSize, &BootOptions[Index].ExitData); @@ -579,19 +678,28 @@ UefiMain( gBS->SetWatchdogTimer(0, 0, 0, NULL); // - // Locate, load, start and configure the driver + // Query the console input handle for the Simple Text Input Ex protocol // - CONST EFI_STATUS DriverStatus = StartAndConfigureDriver(ImageHandle, SystemTable); - if (DriverStatus == EFI_ALREADY_STARTED) - return EFI_SUCCESS; + gBS->HandleProtocol(gST->ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&mTextInputEx); + // + // Allow user to configure the driver by pressing a hotkey + // + Print(L"Press <HOME> to configure EfiGuard...\r\n"); + CONST BOOLEAN InteractiveConfiguration = WaitForKeyWithTimeout(1500) == SCAN_HOME; + + // + // Locate, load, start and configure the driver + // + CONST EFI_STATUS DriverStatus = StartEfiGuard(InteractiveConfiguration); if (EFI_ERROR(DriverStatus)) { Print(L"\r\nERROR: driver load failed with status %llx (%r).\r\n" L"Press any key to continue, or press ESC to return to the firmware or shell.\r\n", DriverStatus, DriverStatus); - if (!WaitForKey()) + if (WaitForKey() == SCAN_ESC) { + gBS->Exit(gImageHandle, DriverStatus, 0, NULL); return DriverStatus; } } diff --git a/Application/Loader/Loader.inf b/Application/Loader/Loader.inf index e817bd5..8d98034 100644 --- a/Application/Loader/Loader.inf +++ b/Application/Loader/Loader.inf @@ -14,13 +14,13 @@ MdePkg/MdePkg.dec EfiGuardPkg/EfiGuardPkg.dec MdeModulePkg/MdeModulePkg.dec - OvmfPkg/OvmfPkg.dec [LibraryClasses] UefiApplicationEntryPoint UefiBootServicesTableLib DebugLib UefiLib + ReportStatusCodeLib DevicePathLib PrintLib UefiBootManagerLib @@ -28,6 +28,8 @@ [Guids] ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" (The boot option of current boot) gEfiGlobalVariableGuid + ## SOMETIMES_PRODUCES ## Variable:L"MemoryTypeInformation." + gEfiMemoryTypeInformationGuid ## SOMETIMES_PRODUCES gEfiEventReadyToBootGuid ## SOMETIMES_PRODUCES gEfiHobListGuid ## CONSUMES gEfiDxeServicesTableGuid ## CONSUMES @@ -52,9 +54,15 @@ gEfiUsbIoProtocolGuid ## CONSUMES gEfiFirmwareVolume2ProtocolGuid ## CONSUMES gEfiSimpleTextInProtocolGuid ## CONSUMES + gEfiSimpleTextInputExProtocolGuid ## CONSUMES gEfiSimpleTextOutProtocolGuid ## CONSUMES gEfiLegacyBiosProtocolGuid ## CONSUMES +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart ## SOMETIMES_CONSUMES + [BuildOptions.Common] *:DEBUG_*_*_PP_FLAGS = -D EFI_DEBUG *:DEBUG_*_*_CC_FLAGS = -D EFI_DEBUG diff --git a/Application/Loader/Loader.vcxproj b/Application/Loader/Loader.vcxproj index 512b624..9254ab7 100644 --- a/Application/Loader/Loader.vcxproj +++ b/Application/Loader/Loader.vcxproj @@ -19,13 +19,15 @@ <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>Unicode</CharacterSet> <SpectreMitigation>false</SpectreMitigation> + <VcpkgEnabled>false</VcpkgEnabled> + <EnableStdModules>false</EnableStdModules> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(SolutionDir)\EfiGuard.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ItemDefinitionGroup> <ClCompile> - <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">CONFIGURE_DRIVER=1;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_PCD_GET_MODE_32_PcdProgressCodeOsLoaderLoad=0x3058000;_PCD_GET_MODE_32_PcdProgressCodeOsLoaderStart=0x3058001;%(PreprocessorDefinitions)</PreprocessorDefinitions> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)Include;$(EDK_PATH)\OvmfPkg\Csm\Include</AdditionalIncludeDirectories> </ClCompile> <Link> |