├── .vscode └── c_cpp_properties.json ├── README.md ├── assets └── logo.png ├── client └── efi-mapper │ ├── LICENSE.txt │ ├── kdmapper.sln │ └── kdmapper │ ├── efi_driver.cpp │ ├── efi_driver.hpp │ ├── kdmapper.cpp │ ├── kdmapper.hpp │ ├── kdmapper.vcxproj │ ├── main.cpp │ ├── nt.hpp │ ├── portable_executable.cpp │ ├── portable_executable.hpp │ ├── service.cpp │ ├── service.hpp │ ├── utils.cpp │ └── utils.hpp └── driver ├── LICENSE.txt ├── Makefile ├── dummy.h ├── general.h └── main.c /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "/usr/include/efi", 8 | "/usr/include/efi/x86_64", 9 | "/usr/include/efi/protocol" 10 | ], 11 | "defines": [], 12 | "compilerPath": "/usr/bin/gcc", 13 | "cStandard": "c11", 14 | "cppStandard": "c++17", 15 | "intelliSenseMode": "gcc-x64" 16 | } 17 | ], 18 | "version": 4 19 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Archivation note:** I put this together when I was 16, and as you can imagine, the code and repo quality reflect that. For example, [this](https://github.com/SamuelTulach/efi-memory/blob/master/driver/main.c#L9) was caused by a [different calling convention (ABI)](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170), and it worked just by pure luck in older OS versions. 2 | 3 | --- 4 | 5 |

6 | 7 |

8 | 9 | Efi-memory is a proof-of-concept EFI runtime driver for reading and writing to virtual memory. It uses [EfiGuards](https://github.com/Mattiwatti/EfiGuard/) method of hooking SetVariable to communicate with the user-mode process. [Here is an example how it works](https://youtu.be/XKODdIsTgzU). 10 | 11 | ## Repo content 12 | driver/ 13 | - EFI driver itself 14 | 15 | client/efi-mapper/ 16 | - [kdmapper](https://github.com/z175/kdmapper/) fork that uses efi-memory to manual map any Windows driver 17 | 18 | ## Compiling 19 | Compiling any of the example client programs is pretty simple. Open the solution file in Visual Studio and compile the project with it's default settings. 20 | 21 | Compiling the driver is also pretty simple. First you need a working Linux install (or you can use Linux subsystem for Windows) and install gnu-efi (commands for Ubuntu 20.04): 22 | ``` 23 | sudo apt install gnu-efi build-essential 24 | ``` 25 | That's all you need to install. Package manager (in the example apt) should take care of all the depencies for you. Once the installation is complete, clone this repo (make sure you have git installed): 26 | ``` 27 | git clone https://github.com/SamuelTulach/efi-memory 28 | ``` 29 | Than navigate to the driver folder and compile the driver with make: 30 | ``` 31 | cd efi-memory 32 | cd driver 33 | make 34 | ``` 35 | If the compile was successful, you should now see memory.efi in the driver folder. 36 | 37 | ## Usage 38 | In order to use the efi-memory driver, you need to load it. First, obtain a copy of memory.efi ([compile it](https://github.com/SamuelTulach/efi-memory#compiling) or [download it from release section](https://github.com/SamuelTulach/efi-memory/releases)) and a copy of [EDK2 efi shell](https://github.com/tianocore/edk2/releases). Now follow these steps: 39 | 40 | 1. Extract downloaded efi shell and rename file Shell.efi (should be in folder UefiShell/X64) to bootx64.efi 41 | 2. Format some USB drive to FAT32 42 | 3. Create following folder structure: 43 | ``` 44 | USB:. 45 | │ memory.efi 46 | │ 47 | └───EFI 48 | └───Boot 49 | bootx64.efi 50 | ``` 51 | 4. Boot from the USB drive 52 | 5. An UEFI shell should start, change directory to your USB (FS0 should be the USB since we are booting from it) and list files: 53 | ``` 54 | FS0: 55 | ls 56 | ``` 57 | 6. You should see file memory.efi, if you do, load it: 58 | ``` 59 | load memory.efi 60 | ``` 61 | 7. Now there should be a nice efi-memory ascii logo printed in your UEFI shell. If there is, the driver was loaded successfuly. If that is the case, type `exit` to start standard boot procedure (while Windows is booting the screen should go blue with confirmation text) 62 | 63 | ## Thanks 64 | I would like to thank [@z175](https://github.com/z175/) for kdmapper project since that is a masterpiece. [@Mattiwatti](https://github.com/Mattiwatti/) for EfiGuard project and the idea of SetVariable hooking. Roderick W. Smith for [rodsbooks.com](http://rodsbooks.com/) (really useful site to read about EFI basics). 65 | 66 | ## License 67 | This repo is licensed under MIT if not stated otherwise in subfolders. 68 | -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SamuelTulach/efi-memory/33a9896b7b42725ae9020b354ee3bce59af91976/assets/logo.png -------------------------------------------------------------------------------- /client/efi-mapper/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Samuel Tulach 4 | Copyright (c) 2019 z175 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2019 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kdmapper", "kdmapper\kdmapper.vcxproj", "{518E0636-BA8F-459D-ACAC-81BD33475E3E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x64.ActiveCfg = Debug|x64 17 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x64.Build.0 = Debug|x64 18 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x86.ActiveCfg = Debug|Win32 19 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Debug|x86.Build.0 = Debug|Win32 20 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x64.ActiveCfg = Release|x64 21 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x64.Build.0 = Release|x64 22 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x86.ActiveCfg = Release|Win32 23 | {518E0636-BA8F-459D-ACAC-81BD33475E3E}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {83D5D338-2A6D-49D5-B1DF-BDD34FB5CC9F} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/efi_driver.cpp: -------------------------------------------------------------------------------- 1 | #include "efi_driver.hpp" 2 | 3 | NTSTATUS efi_driver::SetSystemEnvironmentPrivilege(BOOLEAN Enable, PBOOLEAN WasEnabled) 4 | { 5 | if (WasEnabled != nullptr) 6 | *WasEnabled = FALSE; 7 | 8 | BOOLEAN SeSystemEnvironmentWasEnabled; 9 | const NTSTATUS Status = nt::RtlAdjustPrivilege(SE_SYSTEM_ENVIRONMENT_PRIVILEGE, 10 | Enable, 11 | FALSE, 12 | &SeSystemEnvironmentWasEnabled); 13 | 14 | if (NT_SUCCESS(Status) && WasEnabled != nullptr) 15 | *WasEnabled = SeSystemEnvironmentWasEnabled; 16 | 17 | return Status; 18 | } 19 | 20 | GUID DummyGuid 21 | = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } }; 22 | void efi_driver::SendCommand(MemoryCommand* cmd) 23 | { 24 | UNICODE_STRING VariableName = RTL_CONSTANT_STRING(VARIABLE_NAME); 25 | nt::NtSetSystemEnvironmentValueEx(&VariableName, 26 | &DummyGuid, 27 | cmd, 28 | sizeof(MemoryCommand), 29 | ATTRIBUTES); 30 | } 31 | 32 | bool efi_driver::Init() 33 | { 34 | BOOLEAN SeSystemEnvironmentWasEnabled; 35 | NTSTATUS status = SetSystemEnvironmentPrivilege(true, &SeSystemEnvironmentWasEnabled); 36 | return NT_SUCCESS(status); 37 | } 38 | 39 | bool efi_driver::MemCopy(HANDLE device_handle, uint64_t destination, uint64_t source, uint64_t size) 40 | { 41 | MemoryCommand* cmd = new MemoryCommand(); 42 | cmd->operation = 0; 43 | cmd->magic = COMMAND_MAGIC; 44 | 45 | uintptr_t data[10]; 46 | data[0] = destination; 47 | data[1] = source; 48 | 49 | memcpy(&cmd->data, &data[0], sizeof(data)); 50 | 51 | cmd->size = (int)size; 52 | 53 | SendCommand(cmd); 54 | 55 | return true; // yolo 56 | } 57 | 58 | bool efi_driver::SetMemory(HANDLE device_handle, uint64_t address, uint32_t value, uint64_t size) 59 | { 60 | for (int i = 0; i < size; i++) 61 | { 62 | MemCopy(device_handle, address + i, (uintptr_t)&value, sizeof(uint32_t)); 63 | } 64 | 65 | return true; 66 | } 67 | 68 | bool efi_driver::ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) 69 | { 70 | return MemCopy(device_handle, reinterpret_cast(buffer), address, size); 71 | } 72 | 73 | bool efi_driver::WriteMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size) 74 | { 75 | return MemCopy(device_handle, address, reinterpret_cast(buffer), size); 76 | } 77 | 78 | uint64_t efi_driver::AllocatePool(HANDLE device_handle, nt::POOL_TYPE pool_type, uint64_t size) 79 | { 80 | if (!size) 81 | return 0; 82 | 83 | static uint64_t kernel_ExAllocatePool = 0; 84 | 85 | if (!kernel_ExAllocatePool) 86 | kernel_ExAllocatePool = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExAllocatePool"); 87 | 88 | uint64_t allocated_pool = 0; 89 | 90 | MemoryCommand* cmd = new MemoryCommand(); 91 | cmd->operation = 1; 92 | cmd->magic = COMMAND_MAGIC; 93 | 94 | uintptr_t data[10]; 95 | data[0] = kernel_ExAllocatePool; 96 | data[1] = pool_type; 97 | data[2] = size; 98 | data[3] = (uintptr_t)&allocated_pool; 99 | 100 | memcpy(&cmd->data, &data[0], sizeof(data)); 101 | 102 | SendCommand(cmd); 103 | 104 | return allocated_pool; 105 | } 106 | 107 | bool efi_driver::FreePool(HANDLE device_handle, uint64_t address) 108 | { 109 | if (!address) 110 | return 0; 111 | 112 | static uint64_t kernel_ExFreePool = 0; 113 | 114 | if (!kernel_ExFreePool) 115 | kernel_ExFreePool = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExFreePool"); 116 | 117 | MemoryCommand* cmd = new MemoryCommand(); 118 | cmd->operation = 2; 119 | cmd->magic = COMMAND_MAGIC; 120 | 121 | uintptr_t data[10]; 122 | data[0] = kernel_ExFreePool; 123 | data[1] = address; 124 | 125 | memcpy(&cmd->data, &data[0], sizeof(data)); 126 | 127 | SendCommand(cmd); 128 | 129 | return true; // yolo? 130 | } 131 | 132 | uint64_t efi_driver::GetKernelModuleExport(HANDLE device_handle, uint64_t kernel_module_base, const std::string & function_name) 133 | { 134 | if (!kernel_module_base) 135 | return 0; 136 | 137 | IMAGE_DOS_HEADER dos_header = { 0 }; 138 | IMAGE_NT_HEADERS64 nt_headers = { 0 }; 139 | 140 | if (!ReadMemory(device_handle, kernel_module_base, &dos_header, sizeof(dos_header)) || dos_header.e_magic != IMAGE_DOS_SIGNATURE || 141 | !ReadMemory(device_handle, kernel_module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)) || nt_headers.Signature != IMAGE_NT_SIGNATURE) 142 | return 0; 143 | 144 | const auto export_base = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 145 | const auto export_base_size = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; 146 | 147 | if (!export_base || !export_base_size) 148 | return 0; 149 | 150 | const auto export_data = reinterpret_cast(VirtualAlloc(nullptr, export_base_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); 151 | 152 | if (!ReadMemory(device_handle, kernel_module_base + export_base, export_data, export_base_size)) 153 | { 154 | VirtualFree(export_data, 0, MEM_RELEASE); 155 | return 0; 156 | } 157 | 158 | const auto delta = reinterpret_cast(export_data) - export_base; 159 | 160 | const auto name_table = reinterpret_cast(export_data->AddressOfNames + delta); 161 | const auto ordinal_table = reinterpret_cast(export_data->AddressOfNameOrdinals + delta); 162 | const auto function_table = reinterpret_cast(export_data->AddressOfFunctions + delta); 163 | 164 | for (auto i = 0u; i < export_data->NumberOfNames; ++i) 165 | { 166 | const std::string current_function_name = std::string(reinterpret_cast(name_table[i] + delta)); 167 | 168 | if (!_stricmp(current_function_name.c_str(), function_name.c_str())) 169 | { 170 | const auto function_ordinal = ordinal_table[i]; 171 | const auto function_address = kernel_module_base + function_table[function_ordinal]; 172 | 173 | if (function_address >= kernel_module_base + export_base && function_address <= kernel_module_base + export_base + export_base_size) 174 | { 175 | VirtualFree(export_data, 0, MEM_RELEASE); 176 | return 0; // No forwarded exports on 64bit? 177 | } 178 | 179 | VirtualFree(export_data, 0, MEM_RELEASE); 180 | return function_address; 181 | } 182 | } 183 | 184 | VirtualFree(export_data, 0, MEM_RELEASE); 185 | return 0; 186 | } 187 | 188 | bool efi_driver::GetNtGdiDdDDIReclaimAllocations2KernelInfo(HANDLE device_handle, uint64_t * out_kernel_function_ptr, uint64_t * out_kernel_original_function_address) 189 | { 190 | // 488b05650e1400 mov rax, qword ptr [rip+offset] 191 | // ff150f211600 call cs:__guard_dispatch_icall_fptr 192 | 193 | static uint64_t kernel_function_ptr = 0; 194 | static uint64_t kernel_original_function_address = 0; 195 | 196 | if (!kernel_function_ptr || !kernel_original_function_address) 197 | { 198 | const uint64_t kernel_NtGdiDdDDIReclaimAllocations2 = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("win32kbase.sys"), "NtGdiDdDDIReclaimAllocations2"); 199 | 200 | if (!kernel_NtGdiDdDDIReclaimAllocations2) 201 | { 202 | std::cout << "[-] Failed to get export win32kbase.NtGdiDdDDIReclaimAllocations2" << std::endl; 203 | return false; 204 | } 205 | 206 | const uint64_t kernel_function_ptr_offset_address = kernel_NtGdiDdDDIReclaimAllocations2 + 0x7; 207 | int32_t function_ptr_offset = 0; // offset is a SIGNED integer 208 | 209 | if (!ReadMemory(device_handle, kernel_function_ptr_offset_address, &function_ptr_offset, sizeof(function_ptr_offset))) 210 | return false; 211 | 212 | kernel_function_ptr = kernel_NtGdiDdDDIReclaimAllocations2 + 0xB + function_ptr_offset; 213 | 214 | if (!ReadMemory(device_handle, kernel_function_ptr, &kernel_original_function_address, sizeof(kernel_original_function_address))) 215 | return false; 216 | } 217 | 218 | *out_kernel_function_ptr = kernel_function_ptr; 219 | *out_kernel_original_function_address = kernel_original_function_address; 220 | 221 | return true; 222 | } 223 | 224 | bool efi_driver::GetNtGdiGetCOPPCompatibleOPMInformationInfo(HANDLE device_handle, uint64_t* out_kernel_function_ptr, uint8_t* out_kernel_original_bytes) 225 | { 226 | // 48ff2551d81f00 jmp cs:__imp_NtGdiGetCOPPCompatibleOPMInformation 227 | // cccccccccc padding 228 | 229 | static uint64_t kernel_function_ptr = 0; 230 | static uint8_t kernel_original_jmp_bytes[12] = { 0 }; 231 | 232 | if (!kernel_function_ptr || kernel_original_jmp_bytes[0] == 0) 233 | { 234 | const uint64_t kernel_NtGdiGetCOPPCompatibleOPMInformation = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("win32kfull.sys"), "NtGdiGetCOPPCompatibleOPMInformation"); 235 | 236 | if (!kernel_NtGdiGetCOPPCompatibleOPMInformation) 237 | { 238 | std::cout << "[-] Failed to get export win32kfull.NtGdiGetCOPPCompatibleOPMInformation" << std::endl; 239 | return false; 240 | } 241 | 242 | kernel_function_ptr = kernel_NtGdiGetCOPPCompatibleOPMInformation; 243 | 244 | if (!ReadMemory(device_handle, kernel_function_ptr, kernel_original_jmp_bytes, sizeof(kernel_original_jmp_bytes))) 245 | return false; 246 | } 247 | 248 | *out_kernel_function_ptr = kernel_function_ptr; 249 | memcpy(out_kernel_original_bytes, kernel_original_jmp_bytes, sizeof(kernel_original_jmp_bytes)); 250 | 251 | return true; 252 | } 253 | 254 | bool efi_driver::ClearMmUnloadedDrivers(HANDLE device_handle) 255 | { 256 | ULONG buffer_size = 0; 257 | void* buffer = nullptr; 258 | 259 | NTSTATUS status = NtQuerySystemInformation(static_cast(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size); 260 | 261 | while (status == nt::STATUS_INFO_LENGTH_MISMATCH) 262 | { 263 | VirtualFree(buffer, 0, MEM_RELEASE); 264 | 265 | buffer = VirtualAlloc(nullptr, buffer_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 266 | status = NtQuerySystemInformation(static_cast(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size); 267 | } 268 | 269 | if (!NT_SUCCESS(status)) 270 | { 271 | VirtualFree(buffer, 0, MEM_RELEASE); 272 | return false; 273 | } 274 | 275 | uint64_t object = 0; 276 | 277 | auto system_handle_inforamtion = static_cast(buffer); 278 | 279 | for (auto i = 0u; i < system_handle_inforamtion->HandleCount; ++i) 280 | { 281 | const nt::SYSTEM_HANDLE current_system_handle = system_handle_inforamtion->Handles[i]; 282 | 283 | if (current_system_handle.UniqueProcessId != reinterpret_cast(static_cast(GetCurrentProcessId()))) 284 | continue; 285 | 286 | if (current_system_handle.HandleValue == device_handle) 287 | { 288 | object = reinterpret_cast(current_system_handle.Object); 289 | break; 290 | } 291 | } 292 | 293 | VirtualFree(buffer, 0, MEM_RELEASE); 294 | 295 | if (!object) 296 | return false; 297 | 298 | uint64_t device_object = 0; 299 | 300 | if (!ReadMemory(device_handle, object + 0x8, &device_object, sizeof(device_object))) 301 | return false; 302 | 303 | uint64_t driver_object = 0; 304 | 305 | if (!ReadMemory(device_handle, device_object + 0x8, &driver_object, sizeof(driver_object))) 306 | return false; 307 | 308 | uint64_t driver_section = 0; 309 | 310 | if (!ReadMemory(device_handle, driver_object + 0x28, &driver_section, sizeof(driver_section))) 311 | return false; 312 | 313 | UNICODE_STRING us_driver_base_dll_name = { 0 }; 314 | 315 | if (!ReadMemory(device_handle, driver_section + 0x58, &us_driver_base_dll_name, sizeof(us_driver_base_dll_name))) 316 | return false; 317 | 318 | us_driver_base_dll_name.Length = 0; 319 | 320 | if (!WriteMemory(device_handle, driver_section + 0x58, &us_driver_base_dll_name, sizeof(us_driver_base_dll_name))) 321 | return false; 322 | 323 | return true; 324 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/efi_driver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "service.hpp" 9 | #include "utils.hpp" 10 | 11 | namespace efi_driver 12 | { 13 | typedef struct _MemoryCommand 14 | { 15 | int magic; 16 | int operation; 17 | unsigned long long data[10]; 18 | int size; 19 | } MemoryCommand; 20 | 21 | #define VARIABLE_NAME L"yromeMifE" // EfiMemory 22 | #define COMMAND_MAGIC 0xDEAD 23 | 24 | #define EFI_VARIABLE_NON_VOLATILE 0x00000001 25 | #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 26 | #define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 27 | #define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 28 | #define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 29 | #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 30 | #define EFI_VARIABLE_APPEND_WRITE 0x00000040 31 | #define ATTRIBUTES (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS) 32 | 33 | #define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L) 34 | 35 | bool Init(); 36 | NTSTATUS SetSystemEnvironmentPrivilege(BOOLEAN Enable, PBOOLEAN WasEnabled); 37 | void SendCommand(MemoryCommand* cmd); 38 | 39 | bool MemCopy(HANDLE device_handle, uint64_t destination, uint64_t source, uint64_t size); 40 | bool SetMemory(HANDLE device_handle, uint64_t address, uint32_t value, uint64_t size); 41 | bool ReadMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size); 42 | bool WriteMemory(HANDLE device_handle, uint64_t address, void* buffer, uint64_t size); 43 | uint64_t AllocatePool(HANDLE device_handle, nt::POOL_TYPE pool_type, uint64_t size); 44 | bool FreePool(HANDLE device_handle, uint64_t address); 45 | uint64_t GetKernelModuleExport(HANDLE device_handle, uint64_t kernel_module_base, const std::string& function_name); 46 | bool GetNtGdiDdDDIReclaimAllocations2KernelInfo(HANDLE device_handle, uint64_t* out_kernel_function_ptr, uint64_t* out_kernel_original_function_address); 47 | bool GetNtGdiGetCOPPCompatibleOPMInformationInfo(HANDLE device_handle, uint64_t* out_kernel_function_ptr, uint8_t* out_kernel_original_bytes); 48 | bool ClearMmUnloadedDrivers(HANDLE device_handle); 49 | } 50 | -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/kdmapper.cpp: -------------------------------------------------------------------------------- 1 | #include "kdmapper.hpp" 2 | 3 | uint64_t kdmapper::MapDriver(HANDLE iqvw64e_device_handle, const std::string& driver_path) 4 | { 5 | std::vector raw_image = { 0 }; 6 | 7 | if (!utils::ReadFileToMemory(driver_path, &raw_image)) 8 | { 9 | std::cout << "[-] Failed to read image to memory" << std::endl; 10 | return 0; 11 | } 12 | 13 | const PIMAGE_NT_HEADERS64 nt_headers = portable_executable::GetNtHeaders(raw_image.data()); 14 | 15 | if (!nt_headers) 16 | { 17 | std::cout << "[-] Invalid format of PE image" << std::endl; 18 | return 0; 19 | } 20 | 21 | if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) 22 | { 23 | std::cout << "[-] Image is not 64 bit" << std::endl; 24 | return 0; 25 | } 26 | 27 | const uint32_t image_size = nt_headers->OptionalHeader.SizeOfImage; 28 | 29 | void* local_image_base = VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 30 | uint64_t kernel_image_base = efi_driver::AllocatePool(iqvw64e_device_handle, nt::NonPagedPool, image_size); 31 | 32 | do 33 | { 34 | if (!kernel_image_base) 35 | { 36 | std::cout << "[-] Failed to allocate remote image in kernel" << std::endl; 37 | break; 38 | } 39 | 40 | std::cout << "[+] Image base has been allocated at 0x" << reinterpret_cast(kernel_image_base) << std::endl; 41 | 42 | // Copy image headers 43 | 44 | memcpy(local_image_base, raw_image.data(), nt_headers->OptionalHeader.SizeOfHeaders); 45 | 46 | // Copy image sections 47 | 48 | const PIMAGE_SECTION_HEADER current_image_section = IMAGE_FIRST_SECTION(nt_headers); 49 | 50 | for (auto i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i) 51 | { 52 | auto local_section = reinterpret_cast(reinterpret_cast(local_image_base) + current_image_section[i].VirtualAddress); 53 | memcpy(local_section, reinterpret_cast(reinterpret_cast(raw_image.data()) + current_image_section[i].PointerToRawData), current_image_section[i].SizeOfRawData); 54 | } 55 | 56 | // Resolve relocs and imports 57 | 58 | RelocateImageByDelta(portable_executable::GetRelocs(local_image_base), kernel_image_base - nt_headers->OptionalHeader.ImageBase); 59 | 60 | if (!ResolveImports(iqvw64e_device_handle, portable_executable::GetImports(local_image_base))) 61 | { 62 | std::cout << "[-] Failed to resolve imports" << std::endl; 63 | break; 64 | } 65 | 66 | // Write fixed image to kernel 67 | 68 | if (!efi_driver::WriteMemory(iqvw64e_device_handle, kernel_image_base, local_image_base, image_size)) 69 | { 70 | std::cout << "[-] Failed to write local image to remote image" << std::endl; 71 | break; 72 | } 73 | 74 | VirtualFree(local_image_base, 0, MEM_RELEASE); 75 | 76 | // Call driver entry point 77 | 78 | const uint64_t address_of_entry_point = kernel_image_base + nt_headers->OptionalHeader.AddressOfEntryPoint; 79 | 80 | std::cout << "[<] Calling DriverEntry 0x" << reinterpret_cast(address_of_entry_point) << std::endl; 81 | 82 | long status = 0; // NTSTATUS 83 | 84 | efi_driver::MemoryCommand* cmd = new efi_driver::MemoryCommand(); 85 | cmd->operation = 5; 86 | cmd->magic = COMMAND_MAGIC; 87 | 88 | uintptr_t data[10]; 89 | data[0] = address_of_entry_point; 90 | data[1] = (uintptr_t)&status; 91 | 92 | memcpy(&cmd->data, &data[0], sizeof(data)); 93 | 94 | efi_driver::SendCommand(cmd); 95 | 96 | std::cout << "[+] DriverEntry returned 0x" << std::hex << std::setw(8) << std::setfill('0') << std::uppercase << status << std::nouppercase << std::dec << std::endl; 97 | 98 | // Erase PE headers 99 | efi_driver::SetMemory(iqvw64e_device_handle, kernel_image_base, 0, nt_headers->OptionalHeader.SizeOfHeaders); 100 | return kernel_image_base; 101 | 102 | } while (false); 103 | 104 | VirtualFree(local_image_base, 0, MEM_RELEASE); 105 | efi_driver::FreePool(iqvw64e_device_handle, kernel_image_base); 106 | 107 | return 0; 108 | } 109 | 110 | void kdmapper::RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta) 111 | { 112 | for (const auto& current_reloc : relocs) 113 | { 114 | for (auto i = 0u; i < current_reloc.count; ++i) 115 | { 116 | const uint16_t type = current_reloc.item[i] >> 12; 117 | const uint16_t offset = current_reloc.item[i] & 0xFFF; 118 | 119 | if (type == IMAGE_REL_BASED_DIR64) 120 | * reinterpret_cast(current_reloc.address + offset) += delta; 121 | } 122 | } 123 | } 124 | 125 | bool kdmapper::ResolveImports(HANDLE iqvw64e_device_handle, portable_executable::vec_imports imports) 126 | { 127 | for (const auto& current_import : imports) 128 | { 129 | if (!utils::GetKernelModuleAddress(current_import.module_name)) 130 | { 131 | std::cout << "[-] Dependency " << current_import.module_name << " wasn't found" << std::endl; 132 | return false; 133 | } 134 | 135 | for (auto& current_function_data : current_import.function_datas) 136 | { 137 | const uint64_t function_address = efi_driver::GetKernelModuleExport(iqvw64e_device_handle, utils::GetKernelModuleAddress(current_import.module_name), current_function_data.name); 138 | 139 | if (!function_address) 140 | { 141 | std::cout << "[-] Failed to resolve import " << current_function_data.name << " (" << current_import.module_name << ")" << std::endl; 142 | return false; 143 | } 144 | 145 | *current_function_data.address = function_address; 146 | } 147 | } 148 | 149 | return true; 150 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/kdmapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "portable_executable.hpp" 10 | #include "utils.hpp" 11 | #include "nt.hpp" 12 | #include "efi_driver.hpp" 13 | 14 | namespace kdmapper 15 | { 16 | uint64_t MapDriver(HANDLE iqvw64e_device_handle, const std::string& driver_path); 17 | void RelocateImageByDelta(portable_executable::vec_relocs relocs, const uint64_t delta); 18 | bool ResolveImports(HANDLE iqvw64e_device_handle, portable_executable::vec_imports imports); 19 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/kdmapper.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {518E0636-BA8F-459D-ACAC-81BD33475E3E} 24 | kdmapper 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v142 45 | MultiByte 46 | false 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | MultiByte 54 | false 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Level3 78 | Disabled 79 | true 80 | true 81 | 82 | 83 | 84 | 85 | Level4 86 | true 87 | true 88 | stdcpp17 89 | false 90 | 91 | 92 | version.lib;%(AdditionalDependencies) 93 | 94 | 95 | 96 | 97 | Level3 98 | MaxSpeed 99 | true 100 | true 101 | true 102 | true 103 | 104 | 105 | true 106 | true 107 | 108 | 109 | 110 | 111 | Level4 112 | MaxSpeed 113 | true 114 | true 115 | true 116 | true 117 | true 118 | stdcpp17 119 | 120 | 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/main.cpp: -------------------------------------------------------------------------------- 1 | #include "kdmapper.hpp" 2 | 3 | int main(const int argc, char** argv) 4 | { 5 | if (argc != 2 || std::filesystem::path(argv[1]).extension().string().compare(".sys")) 6 | { 7 | std::cout << "[-] Incorrect usage" << std::endl; 8 | return -1; 9 | } 10 | 11 | const std::string driver_path = argv[1]; 12 | 13 | if (!std::filesystem::exists(driver_path)) 14 | { 15 | std::cout << "[-] File " << driver_path << " doesn't exist" << std::endl; 16 | return -1; 17 | } 18 | 19 | HANDLE iqvw64e_device_handle = nullptr; // dummy handle because I am lazy piece of shit 20 | 21 | bool status = efi_driver::Init(); 22 | if (!status) 23 | { 24 | std::cout << "[-] Failed to init driver" << std::endl; 25 | return -1; 26 | } 27 | 28 | if (!kdmapper::MapDriver(iqvw64e_device_handle, driver_path)) 29 | { 30 | std::cout << "[-] Failed to map " << driver_path << std::endl; 31 | return -1; 32 | } 33 | 34 | std::cout << "[+] success" << std::endl; 35 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/nt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #pragma comment(lib, "ntdll.lib") 5 | 6 | namespace nt 7 | { 8 | constexpr auto PAGE_SIZE = 0x1000; 9 | constexpr auto STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; 10 | 11 | constexpr auto SystemModuleInformation = 11; 12 | constexpr auto SystemHandleInformation = 16; 13 | constexpr auto SystemExtendedHandleInformation = 64; 14 | 15 | typedef struct _SYSTEM_HANDLE 16 | { 17 | PVOID Object; 18 | HANDLE UniqueProcessId; 19 | HANDLE HandleValue; 20 | ULONG GrantedAccess; 21 | USHORT CreatorBackTraceIndex; 22 | USHORT ObjectTypeIndex; 23 | ULONG HandleAttributes; 24 | ULONG Reserved; 25 | } SYSTEM_HANDLE, *PSYSTEM_HANDLE; 26 | 27 | typedef struct _SYSTEM_HANDLE_INFORMATION_EX 28 | { 29 | ULONG_PTR HandleCount; 30 | ULONG_PTR Reserved; 31 | SYSTEM_HANDLE Handles[1]; 32 | } SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; 33 | 34 | typedef enum _POOL_TYPE { 35 | NonPagedPool, 36 | NonPagedPoolExecute, 37 | PagedPool, 38 | NonPagedPoolMustSucceed, 39 | DontUseThisType, 40 | NonPagedPoolCacheAligned, 41 | PagedPoolCacheAligned, 42 | NonPagedPoolCacheAlignedMustS, 43 | MaxPoolType, 44 | NonPagedPoolBase, 45 | NonPagedPoolBaseMustSucceed, 46 | NonPagedPoolBaseCacheAligned, 47 | NonPagedPoolBaseCacheAlignedMustS, 48 | NonPagedPoolSession, 49 | PagedPoolSession, 50 | NonPagedPoolMustSucceedSession, 51 | DontUseThisTypeSession, 52 | NonPagedPoolCacheAlignedSession, 53 | PagedPoolCacheAlignedSession, 54 | NonPagedPoolCacheAlignedMustSSession, 55 | NonPagedPoolNx, 56 | NonPagedPoolNxCacheAligned, 57 | NonPagedPoolSessionNx 58 | } POOL_TYPE; 59 | 60 | typedef struct _RTL_PROCESS_MODULE_INFORMATION 61 | { 62 | HANDLE Section; 63 | PVOID MappedBase; 64 | PVOID ImageBase; 65 | ULONG ImageSize; 66 | ULONG Flags; 67 | USHORT LoadOrderIndex; 68 | USHORT InitOrderIndex; 69 | USHORT LoadCount; 70 | USHORT OffsetToFileName; 71 | UCHAR FullPathName[256]; 72 | } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION; 73 | 74 | typedef struct _RTL_PROCESS_MODULES 75 | { 76 | ULONG NumberOfModules; 77 | RTL_PROCESS_MODULE_INFORMATION Modules[1]; 78 | } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; 79 | 80 | extern "C" 81 | { 82 | NTSYSAPI 83 | NTSTATUS 84 | NTAPI 85 | RtlAdjustPrivilege( 86 | _In_ ULONG Privilege, 87 | _In_ BOOLEAN Enable, 88 | _In_ BOOLEAN Client, 89 | _Out_ PBOOLEAN WasEnabled 90 | ); 91 | 92 | NTSYSCALLAPI 93 | NTSTATUS 94 | NTAPI 95 | NtSetSystemEnvironmentValueEx( 96 | _In_ PUNICODE_STRING VariableName, 97 | _In_ LPGUID VendorGuid, 98 | _In_reads_bytes_opt_(ValueLength) PVOID Value, 99 | _In_ ULONG ValueLength, 100 | _In_ ULONG Attributes 101 | ); 102 | } 103 | 104 | #define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), (PWSTR)s } 105 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/portable_executable.cpp: -------------------------------------------------------------------------------- 1 | #include "portable_executable.hpp" 2 | 3 | PIMAGE_NT_HEADERS64 portable_executable::GetNtHeaders(void* image_base) 4 | { 5 | const auto dos_header = reinterpret_cast(image_base); 6 | 7 | if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) 8 | return nullptr; 9 | 10 | const auto nt_headers = reinterpret_cast(reinterpret_cast(image_base) + dos_header->e_lfanew); 11 | 12 | if (nt_headers->Signature != IMAGE_NT_SIGNATURE) 13 | return nullptr; 14 | 15 | return nt_headers; 16 | } 17 | 18 | portable_executable::vec_relocs portable_executable::GetRelocs(void* image_base) 19 | { 20 | const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base); 21 | 22 | if (!nt_headers) 23 | return {}; 24 | 25 | vec_relocs relocs; 26 | return relocs; // gonna probably kill me for this but for some reason drivers without reallocation seems falsely reporting some shit memory regions causing mapper to crash 27 | 28 | auto current_base_relocation = reinterpret_cast(reinterpret_cast(image_base) + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); 29 | const auto reloc_end = reinterpret_cast(current_base_relocation) + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; 30 | 31 | while (current_base_relocation->VirtualAddress && current_base_relocation->VirtualAddress < reloc_end && current_base_relocation->SizeOfBlock) 32 | { 33 | RelocInfo reloc_info; 34 | 35 | reloc_info.address = reinterpret_cast(image_base) + current_base_relocation->VirtualAddress; 36 | reloc_info.item = reinterpret_cast(reinterpret_cast(current_base_relocation) + sizeof(IMAGE_BASE_RELOCATION)); 37 | reloc_info.count = (current_base_relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t); 38 | 39 | relocs.push_back(reloc_info); 40 | 41 | current_base_relocation = reinterpret_cast(reinterpret_cast(current_base_relocation) + current_base_relocation->SizeOfBlock); 42 | } 43 | 44 | return relocs; 45 | } 46 | 47 | portable_executable::vec_imports portable_executable::GetImports(void* image_base) 48 | { 49 | const PIMAGE_NT_HEADERS64 nt_headers = GetNtHeaders(image_base); 50 | 51 | if (!nt_headers) 52 | return {}; 53 | 54 | vec_imports imports; 55 | 56 | auto current_import_descriptor = reinterpret_cast(reinterpret_cast(image_base) + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 57 | 58 | while (current_import_descriptor->FirstThunk) 59 | { 60 | ImportInfo import_info; 61 | 62 | import_info.module_name = std::string(reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->Name)); 63 | 64 | auto current_first_thunk = reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->FirstThunk); 65 | auto current_originalFirstThunk = reinterpret_cast(reinterpret_cast(image_base) + current_import_descriptor->OriginalFirstThunk); 66 | 67 | while (current_originalFirstThunk->u1.Function) 68 | { 69 | ImportFunctionInfo import_function_data; 70 | 71 | auto thunk_data = reinterpret_cast(reinterpret_cast(image_base) + current_originalFirstThunk->u1.AddressOfData); 72 | 73 | import_function_data.name = thunk_data->Name; 74 | import_function_data.address = ¤t_first_thunk->u1.Function; 75 | 76 | import_info.function_datas.push_back(import_function_data); 77 | 78 | ++current_originalFirstThunk; 79 | ++current_first_thunk; 80 | } 81 | 82 | imports.push_back(import_info); 83 | ++current_import_descriptor; 84 | } 85 | 86 | return imports; 87 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/portable_executable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace portable_executable 8 | { 9 | struct RelocInfo 10 | { 11 | uint64_t address; 12 | uint16_t* item; 13 | uint32_t count; 14 | }; 15 | 16 | struct ImportFunctionInfo 17 | { 18 | std::string name; 19 | uint64_t* address; 20 | }; 21 | 22 | struct ImportInfo 23 | { 24 | std::string module_name; 25 | std::vector function_datas; 26 | }; 27 | 28 | using vec_sections = std::vector; 29 | using vec_relocs = std::vector; 30 | using vec_imports = std::vector; 31 | 32 | PIMAGE_NT_HEADERS64 GetNtHeaders(void* image_base); 33 | vec_relocs GetRelocs(void* image_base); 34 | vec_imports GetImports(void* image_base); 35 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/service.cpp: -------------------------------------------------------------------------------- 1 | #include "service.hpp" 2 | 3 | bool service::RegisterAndStart(const std::string& driver_path) 4 | { 5 | const std::string driver_name = std::filesystem::path(driver_path).filename().string(); 6 | const SC_HANDLE sc_manager_handle = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE); 7 | 8 | if (!sc_manager_handle) 9 | return false; 10 | 11 | SC_HANDLE service_handle = CreateService(sc_manager_handle, driver_name.c_str(), driver_name.c_str(), SERVICE_START | SERVICE_STOP | DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, driver_path.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr); 12 | 13 | if (!service_handle) 14 | { 15 | service_handle = OpenService(sc_manager_handle, driver_name.c_str(), SERVICE_START); 16 | 17 | if (!service_handle) 18 | { 19 | CloseServiceHandle(sc_manager_handle); 20 | return false; 21 | } 22 | } 23 | 24 | const bool result = StartService(service_handle, 0, nullptr); 25 | 26 | CloseServiceHandle(service_handle); 27 | CloseServiceHandle(sc_manager_handle); 28 | 29 | return result; 30 | } 31 | 32 | bool service::StopAndRemove(const std::string& driver_name) 33 | { 34 | const SC_HANDLE sc_manager_handle = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE); 35 | 36 | if (!sc_manager_handle) 37 | return false; 38 | 39 | const SC_HANDLE service_handle = OpenService(sc_manager_handle, driver_name.c_str(), SERVICE_STOP | DELETE); 40 | 41 | if (!service_handle) 42 | { 43 | CloseServiceHandle(sc_manager_handle); 44 | return false; 45 | } 46 | 47 | SERVICE_STATUS status = { 0 }; 48 | const bool result = ControlService(service_handle, SERVICE_CONTROL_STOP, &status) && DeleteService(service_handle); 49 | 50 | CloseServiceHandle(service_handle); 51 | CloseServiceHandle(sc_manager_handle); 52 | 53 | return result; 54 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/service.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace service 7 | { 8 | bool RegisterAndStart(const std::string& driver_path); 9 | bool StopAndRemove(const std::string& driver_name); 10 | }; -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | 3 | bool utils::ReadFileToMemory(const std::string& file_path, std::vector* out_buffer) 4 | { 5 | std::ifstream file_ifstream(file_path, std::ios::binary); 6 | 7 | if (!file_ifstream) 8 | return false; 9 | 10 | out_buffer->assign((std::istreambuf_iterator(file_ifstream)), std::istreambuf_iterator()); 11 | file_ifstream.close(); 12 | 13 | return true; 14 | } 15 | 16 | bool utils::CreateFileFromMemory(const std::string& desired_file_path, const char* address, size_t size) 17 | { 18 | std::ofstream file_ofstream(desired_file_path.c_str(), std::ios_base::out | std::ios_base::binary); 19 | 20 | if (!file_ofstream.write(address, size)) 21 | { 22 | file_ofstream.close(); 23 | return false; 24 | } 25 | 26 | file_ofstream.close(); 27 | return true; 28 | } 29 | 30 | uint64_t utils::GetKernelModuleAddress(const std::string& module_name) 31 | { 32 | void* buffer = nullptr; 33 | DWORD buffer_size = 0; 34 | 35 | NTSTATUS status = NtQuerySystemInformation(static_cast(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size); 36 | 37 | while (status == nt::STATUS_INFO_LENGTH_MISMATCH) 38 | { 39 | VirtualFree(buffer, 0, MEM_RELEASE); 40 | 41 | buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 42 | status = NtQuerySystemInformation(static_cast(nt::SystemModuleInformation), buffer, buffer_size, &buffer_size); 43 | } 44 | 45 | if (!NT_SUCCESS(status)) 46 | { 47 | VirtualFree(buffer, 0, MEM_RELEASE); 48 | return 0; 49 | } 50 | 51 | const auto modules = static_cast(buffer); 52 | 53 | for (auto i = 0u; i < modules->NumberOfModules; ++i) 54 | { 55 | const std::string current_module_name = std::string(reinterpret_cast(modules->Modules[i].FullPathName) + modules->Modules[i].OffsetToFileName); 56 | 57 | if (!_stricmp(current_module_name.c_str(), module_name.c_str())) 58 | { 59 | const uint64_t result = reinterpret_cast(modules->Modules[i].ImageBase); 60 | 61 | VirtualFree(buffer, 0, MEM_RELEASE); 62 | return result; 63 | } 64 | } 65 | 66 | VirtualFree(buffer, 0, MEM_RELEASE); 67 | return 0; 68 | } -------------------------------------------------------------------------------- /client/efi-mapper/kdmapper/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "nt.hpp" 11 | 12 | namespace utils 13 | { 14 | bool ReadFileToMemory(const std::string& file_path, std::vector* out_buffer); 15 | bool CreateFileFromMemory(const std::string& desired_file_path, const char* address, size_t size); 16 | uint64_t GetKernelModuleAddress(const std::string& module_name); 17 | } -------------------------------------------------------------------------------- /driver/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Samuel Tulach (@SamuelTulach) 2 | Copyright (c) 2019 Matthijs Lavrijsen (@Mattiwatti) 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | -------------------------------------------------------------------------------- /driver/Makefile: -------------------------------------------------------------------------------- 1 | ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) 2 | 3 | OBJS = main.o 4 | TARGET = memory.efi 5 | 6 | EFIINC = /usr/include/efi 7 | EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol 8 | LIB32 = /usr/lib32 9 | LIB64 = /usr/lib 10 | 11 | CFLAGS = $(EFIINCS) -fno-stack-protector -fpic \ 12 | -fshort-wchar -mno-red-zone -Wall 13 | 14 | ifeq ($(ARCH),x86_64) 15 | CFLAGS += -DEFI_FUNCTION_WRAPPER 16 | LIB = $(LIB64) 17 | EFILIB = $(LIB64) 18 | endif 19 | 20 | ifeq ($(ARCH),ia32) 21 | LIB = $(LIB32) 22 | EFILIB = $(LIB32) 23 | endif 24 | 25 | EFI_CRT_OBJS = $(EFILIB)/crt0-efi-$(ARCH).o 26 | EFI_LDS = $(EFILIB)/elf_$(ARCH)_efi.lds 27 | 28 | LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \ 29 | -Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS) 30 | 31 | all: $(TARGET) 32 | 33 | memory.so: $(OBJS) 34 | ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi 35 | 36 | %.efi: %.so 37 | objcopy -j .text -j .sdata -j .data -j .dynamic \ 38 | -j .dynsym -j .rel -j .rela -j .reloc \ 39 | --target=efi-rtdrv-$(ARCH) $^ $@ 40 | 41 | clean: 42 | rm -f memory.efi memory.so main.o *~ -------------------------------------------------------------------------------- /driver/dummy.h: -------------------------------------------------------------------------------- 1 | // This header contains dummy functions to hook in runtime services table 2 | // We want to do this since then, the function pointers are going to be pointing 3 | // to somewhat similar memory location 4 | 5 | #include "general.h" 6 | 7 | static EFI_GET_TIME oGetTime; 8 | EFIAPI EFI_STATUS HookedGetTime(EFI_TIME* time, EFI_TIME_CAPABILITIES* capabilities) 9 | { 10 | return oGetTime(time, capabilities); 11 | } 12 | 13 | static EFI_SET_TIME oSetTime; 14 | EFIAPI EFI_STATUS HookedSetTime(EFI_TIME* time) 15 | { 16 | return oSetTime(time); 17 | } 18 | 19 | static EFI_GET_WAKEUP_TIME oGetWakeupTime; 20 | EFIAPI EFI_STATUS HookedGetWakeupTime(BOOLEAN* enabled, BOOLEAN* pending, EFI_TIME* time) 21 | { 22 | return oGetWakeupTime(enabled, pending, time); 23 | } 24 | 25 | static EFI_SET_WAKEUP_TIME oSetWakeupTime; 26 | EFIAPI EFI_STATUS HookedSetWakeupTime(BOOLEAN enable, EFI_TIME* time) 27 | { 28 | return oSetWakeupTime(enable, time); 29 | } 30 | 31 | static EFI_SET_VIRTUAL_ADDRESS_MAP oSetVirtualAddressMap; 32 | EFIAPI EFI_STATUS HookedSetVirtualAddressMap(UINTN mapSize, UINTN descriptorSize, UINT32 version, EFI_MEMORY_DESCRIPTOR* virtualMap) 33 | { 34 | return oSetVirtualAddressMap(mapSize, descriptorSize, version, virtualMap); 35 | } 36 | 37 | static EFI_CONVERT_POINTER oConvertPointer; 38 | EFIAPI EFI_STATUS HookedConvertPointer(UINTN debug, void** address) 39 | { 40 | return oConvertPointer(debug, address); 41 | } 42 | 43 | static EFI_GET_VARIABLE oGetVariable; 44 | EFIAPI EFI_STATUS HookedGetVariable(CHAR16* variableName, EFI_GUID* vendorGuid, UINT32* attributes, UINTN* dataSize, void* data) 45 | { 46 | return oGetVariable(variableName, vendorGuid, attributes, dataSize, data); 47 | } 48 | 49 | static EFI_GET_NEXT_VARIABLE_NAME oGetNextVariableName; 50 | EFIAPI EFI_STATUS HookedGetNextVariableName(UINTN* variableNameSize, CHAR16* variableName, EFI_GUID* vendorGuid) 51 | { 52 | return oGetNextVariableName(variableNameSize, variableName, vendorGuid); 53 | } 54 | 55 | /*static EFI_SET_VARIABLE oSetVariable; 56 | EFIAPI EFI_STATUS HookedSetVariable(CHAR16* variableName, EFI_GUID* vendorGuid, UINT32 attributes, UINTN dataSize, void* data) 57 | { 58 | return oSetVariable(variableName, vendorGuid, attributes, dataSize, data); 59 | }*/ 60 | 61 | static EFI_GET_NEXT_HIGH_MONO_COUNT oGetNextHighMonotonicCount; 62 | EFIAPI EFI_STATUS HookedGetNextHighMonotonicCount(UINT32* highCount) 63 | { 64 | return oGetNextHighMonotonicCount(highCount); 65 | } 66 | 67 | static EFI_RESET_SYSTEM oResetSystem; 68 | EFIAPI EFI_STATUS HookedResetSystem(EFI_RESET_TYPE resetType, EFI_STATUS resetStatus, UINTN dataSize, CHAR16* resetData) 69 | { 70 | return oResetSystem(resetType, resetStatus, dataSize, resetData); 71 | } 72 | 73 | static EFI_UPDATE_CAPSULE oUpdateCapsule; 74 | EFIAPI EFI_STATUS HookedUpdateCapsule(EFI_CAPSULE_HEADER** capsuleHeaderArray, UINTN capsuleCount, EFI_PHYSICAL_ADDRESS scatterGatherList) 75 | { 76 | return oUpdateCapsule(capsuleHeaderArray, capsuleCount, scatterGatherList); 77 | } 78 | 79 | static EFI_QUERY_CAPSULE_CAPABILITIES oQueryCapsuleCapabilities; 80 | EFIAPI EFI_STATUS HookedQueryCapsuleCapabilities(EFI_CAPSULE_HEADER** capsuleHeaderArray, UINTN capsuleCount, UINT64* maximumCapsuleSize, EFI_RESET_TYPE* resetType) 81 | { 82 | return oQueryCapsuleCapabilities(capsuleHeaderArray, capsuleCount, maximumCapsuleSize, resetType); 83 | } 84 | 85 | static EFI_QUERY_VARIABLE_INFO oQueryVariableInfo; 86 | EFIAPI EFI_STATUS HookedQueryVariableInfo(UINT32 attributes, UINT64* maximumVariableStorageSize, UINT64* remainingVariableStorageSize, UINT64* maximumVariableSize) 87 | { 88 | return oQueryVariableInfo(attributes, maximumVariableStorageSize, remainingVariableStorageSize, maximumVariableSize); 89 | } -------------------------------------------------------------------------------- /driver/general.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERAL_H 2 | #define GENERAL_H 3 | 4 | // Since some retard decided to use M$ ABI in EFI standard 5 | // instead of SysV ABI, we now have to do transitions 6 | // GNU-EFI has a functionality for this (thanks god) 7 | #define GNU_EFI_USE_MS_ABI 1 8 | #define stdcall __attribute__((ms_abi)) // wHy NoT tO jUsT uSe MsVc 9 | #define fastcall __attribute__((fastcall)) 10 | 11 | // Mandatory defines 12 | #include 13 | #include 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /driver/main.c: -------------------------------------------------------------------------------- 1 | #include "general.h" 2 | 3 | // Dummy hooks 4 | #include "dummy.h" 5 | 6 | // Since Windows does not want to allocate executable memory for our driver 7 | // in new versions of the OS, then we have to do it ourselves (I guess) 8 | // If you are on Windows 1909 and bellow, please use older version of the mapper 9 | // that use ExAllocatePool 10 | #define DRIVER_SIZE 26214400 // 25mb should be enough 11 | __attribute__((section(".text"))) char DriverBuffer[DRIVER_SIZE]; // It has to be in the text section so it's executable (surprise) 12 | 13 | // Our protocol GUID (should be different for every driver) 14 | static const EFI_GUID ProtocolGuid 15 | = { 0x2b479eea, 0x0ecf, 0x4a46, {0x96, 0x84, 0x8f, 0x14, 0xed, 0x92, 0xd9, 0xec} }; 16 | 17 | // VirtualAddressMap GUID (gEfiEventVirtualAddressChangeGuid) 18 | static const EFI_GUID VirtualGuid 19 | = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }}; 20 | 21 | // ExitBootServices GUID (gEfiEventExitBootServicesGuid) 22 | static const EFI_GUID ExitGuid 23 | = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }}; 24 | 25 | // Dummy protocol struct 26 | typedef struct _DummyProtocalData{ 27 | UINTN blank; 28 | } DummyProtocalData; 29 | 30 | // Pointers to original functions 31 | static EFI_SET_VARIABLE oSetVariable = NULL; 32 | 33 | // Global declarations 34 | static EFI_EVENT NotifyEvent = NULL; 35 | static EFI_EVENT ExitEvent = NULL; 36 | static BOOLEAN Virtual = FALSE; 37 | static BOOLEAN Runtime = FALSE; 38 | 39 | // Defines used to check if call is really coming from client 40 | #define VARIABLE_NAME L"yromeMifE" // EfiMemory 41 | #define COMMAND_MAGIC 0xDEAD 42 | 43 | // Struct containing data used to communicate with the client 44 | typedef struct _MemoryCommand 45 | { 46 | int magic; 47 | int operation; 48 | unsigned long long data[10]; 49 | int size; 50 | } MemoryCommand; 51 | 52 | // Functions (Windows only) 53 | typedef uintptr_t (stdcall *ExAllocatePool)(int type, uintptr_t size); 54 | typedef void (stdcall *ExFreePool)(uintptr_t address); 55 | typedef void (stdcall *StandardFuncStd)(); 56 | typedef void (fastcall *StandardFuncFast)(); 57 | typedef unsigned long (stdcall *DriverEntry)(void* driver, void* registry); 58 | 59 | // Function that actually performs the r/w 60 | EFI_STATUS 61 | RunCommand(MemoryCommand* cmd) 62 | { 63 | // Check if the command has right magic 64 | // (just to be sure again) 65 | if (cmd->magic != COMMAND_MAGIC) 66 | { 67 | return EFI_ACCESS_DENIED; 68 | } 69 | 70 | // Copy operation 71 | if (cmd->operation == 0) 72 | { 73 | // Same as memcpy function 74 | CopyMem(cmd->data[0], cmd->data[1], cmd->size); 75 | 76 | return EFI_SUCCESS; 77 | } 78 | 79 | // "Allocate" memory 80 | if (cmd->operation == 1) 81 | { 82 | if (cmd->data[2] < DRIVER_SIZE) // Only small driver allowed, big drivers bad 83 | { 84 | *(uintptr_t*)cmd->data[3] = &DriverBuffer; // Get rekt windows 85 | } 86 | } 87 | 88 | // Call any void function (__stdcall) 89 | if (cmd->operation == 3) 90 | { 91 | void* function = cmd->data[0]; 92 | StandardFuncStd stand = (StandardFuncStd)function; 93 | stand(); 94 | } 95 | 96 | // Call any void function (__fastcall) 97 | if (cmd->operation == 4) 98 | { 99 | void* function = cmd->data[0]; 100 | StandardFuncFast stand = (StandardFuncFast)function; 101 | stand(); 102 | } 103 | 104 | // Call driver entry 105 | if (cmd->operation == 5) 106 | { 107 | void* function = cmd->data[0]; 108 | DriverEntry entry = (DriverEntry)function; 109 | 110 | // gcc compiles long as 8 byte 111 | // msvc compiles long as 4 byte 112 | // we are gonna use int 113 | // you can't even imagine how long I was fking 114 | // with this 115 | int status = entry(0, 0); 116 | *(int*)cmd->data[1] = status; 117 | } 118 | 119 | // Invalid command 120 | return EFI_UNSUPPORTED; 121 | } 122 | 123 | // Hooked EFI function SetVariable() 124 | // Can be called from Windows with NtSetSystemEnvironmentValueEx 125 | EFI_STATUS 126 | EFIAPI 127 | HookedSetVariable( 128 | IN CHAR16 *VariableName, 129 | IN EFI_GUID *VendorGuid, 130 | IN UINT32 Attributes, 131 | IN UINTN DataSize, 132 | IN VOID *Data 133 | ) 134 | { 135 | // Use our hook only after we are in virtual address-space 136 | if (Virtual && Runtime) 137 | { 138 | // Check of input is not null 139 | if (VariableName != NULL && VariableName[0] != CHAR_NULL && VendorGuid != NULL) 140 | { 141 | // Check if variable name is same as our declared one 142 | // this is used to check if call is really from our program 143 | // running in the OS (client) 144 | if (StrnCmp(VariableName, VARIABLE_NAME, 145 | (sizeof(VARIABLE_NAME) / sizeof(CHAR16)) - 1) == 0) 146 | { 147 | if (DataSize == 0 && Data == NULL) 148 | { 149 | // Skip no data 150 | return EFI_SUCCESS; 151 | } 152 | 153 | // Check if the data size is correct 154 | if (DataSize == sizeof(MemoryCommand)) 155 | { 156 | // We did it! 157 | // Now we can call the magic function 158 | return RunCommand((MemoryCommand*)Data); 159 | } 160 | } 161 | } 162 | } 163 | 164 | // Call the original SetVariable() function 165 | return oSetVariable(VariableName, VendorGuid, Attributes, DataSize, Data); 166 | } 167 | 168 | // Event callback when SetVitualAddressMap() is called by OS 169 | VOID 170 | EFIAPI 171 | SetVirtualAddressMapEvent( 172 | IN EFI_EVENT Event, 173 | IN VOID* Context 174 | ) 175 | { 176 | // Convert orignal SetVariable address 177 | RT->ConvertPointer(0, &oSetVariable); 178 | 179 | // Convert all other addresses 180 | RT->ConvertPointer(0, &oGetTime); 181 | RT->ConvertPointer(0, &oSetTime); 182 | RT->ConvertPointer(0, &oGetWakeupTime); 183 | RT->ConvertPointer(0, &oSetWakeupTime); 184 | RT->ConvertPointer(0, &oSetVirtualAddressMap); 185 | RT->ConvertPointer(0, &oConvertPointer); 186 | RT->ConvertPointer(0, &oGetVariable); 187 | RT->ConvertPointer(0, &oGetNextVariableName); 188 | //RT->ConvertPointer(0, &oSetVariable); 189 | RT->ConvertPointer(0, &oGetNextHighMonotonicCount); 190 | RT->ConvertPointer(0, &oResetSystem); 191 | RT->ConvertPointer(0, &oUpdateCapsule); 192 | RT->ConvertPointer(0, &oQueryCapsuleCapabilities); 193 | RT->ConvertPointer(0, &oQueryVariableInfo); 194 | 195 | // Convert runtime services pointer 196 | RtLibEnableVirtualMappings(); 197 | 198 | // Null and close the event so it does not get called again 199 | NotifyEvent = NULL; 200 | 201 | // We are now working in virtual address-space 202 | Virtual = TRUE; 203 | } 204 | 205 | // Event callback after boot process is started 206 | VOID 207 | EFIAPI 208 | ExitBootServicesEvent( 209 | IN EFI_EVENT Event, 210 | IN VOID* Context 211 | ) 212 | { 213 | // This event is called only once so close it 214 | BS->CloseEvent(ExitEvent); 215 | ExitEvent = NULL; 216 | 217 | // Boot services are now not avaible 218 | BS = NULL; 219 | 220 | // We are booting the OS now 221 | Runtime = TRUE; 222 | 223 | // Print some text so we know it works (300iq) 224 | ST->ConOut->SetAttribute(ST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); 225 | ST->ConOut->ClearScreen(ST->ConOut); 226 | Print(L"Driver seems to be working as expected! Windows is booting now...\n"); 227 | } 228 | 229 | // Replaces service table pointer with desired one 230 | // returns original 231 | VOID* 232 | SetServicePointer( 233 | IN OUT EFI_TABLE_HEADER *ServiceTableHeader, 234 | IN OUT VOID **ServiceTableFunction, 235 | IN VOID *NewFunction 236 | ) 237 | { 238 | // We don't want to fuck up the system 239 | if (ServiceTableFunction == NULL || NewFunction == NULL || *ServiceTableFunction == NULL) 240 | return NULL; 241 | 242 | // Make sure boot services pointers are not null 243 | ASSERT(BS != NULL); 244 | ASSERT(BS->CalculateCrc32 != NULL); 245 | 246 | // Raise task priority level 247 | CONST EFI_TPL Tpl = BS->RaiseTPL(TPL_HIGH_LEVEL); 248 | 249 | // Swap the pointers 250 | // GNU-EFI and InterlockedCompareExchangePointer 251 | // are not friends 252 | VOID* OriginalFunction = *ServiceTableFunction; 253 | *ServiceTableFunction = NewFunction; 254 | 255 | // Change the table CRC32 signature 256 | ServiceTableHeader->CRC32 = 0; 257 | BS->CalculateCrc32((UINT8*)ServiceTableHeader, ServiceTableHeader->HeaderSize, &ServiceTableHeader->CRC32); 258 | 259 | // Restore task priority level 260 | BS->RestoreTPL(Tpl); 261 | 262 | return OriginalFunction; 263 | } 264 | 265 | // EFI driver unload routine 266 | static 267 | EFI_STATUS 268 | EFI_FUNCTION 269 | efi_unload(IN EFI_HANDLE ImageHandle) 270 | { 271 | // We don't want our driver to be unloaded 272 | // until complete reboot 273 | return EFI_ACCESS_DENIED; 274 | } 275 | 276 | // EFI entry point 277 | EFI_STATUS 278 | efi_main(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) 279 | { 280 | // Initialize internal GNU-EFI functions 281 | InitializeLib(ImageHandle, SystemTable); 282 | 283 | // Get handle to this image 284 | EFI_LOADED_IMAGE *LoadedImage = NULL; 285 | EFI_STATUS status = BS->OpenProtocol(ImageHandle, &LoadedImageProtocol, 286 | (void**)&LoadedImage, ImageHandle, 287 | NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 288 | 289 | // Return if protocol failed to open 290 | if (EFI_ERROR(status)) 291 | { 292 | Print(L"Can't open protocol: %d\n", status); 293 | return status; 294 | } 295 | 296 | // Install our protocol interface 297 | // This is needed to keep our driver loaded 298 | DummyProtocalData dummy = { 0 }; 299 | status = LibInstallProtocolInterfaces( 300 | &ImageHandle, &ProtocolGuid, 301 | &dummy, NULL); 302 | 303 | // Return if interface failed to register 304 | if (EFI_ERROR(status)) 305 | { 306 | Print(L"Can't register interface: %d\n", status); 307 | return status; 308 | } 309 | 310 | // Set our image unload routine 311 | LoadedImage->Unload = (EFI_IMAGE_UNLOAD)efi_unload; 312 | 313 | // Create global event for VirtualAddressMap 314 | status = BS->CreateEventEx(EVT_NOTIFY_SIGNAL, 315 | TPL_NOTIFY, 316 | SetVirtualAddressMapEvent, 317 | NULL, 318 | VirtualGuid, 319 | &NotifyEvent); 320 | 321 | // Return if event create failed 322 | if (EFI_ERROR(status)) 323 | { 324 | Print(L"Can't create event (SetVirtualAddressMapEvent): %d\n", status); 325 | return status; 326 | } 327 | 328 | // Create global event for ExitBootServices 329 | status = BS->CreateEventEx(EVT_NOTIFY_SIGNAL, 330 | TPL_NOTIFY, 331 | ExitBootServicesEvent, 332 | NULL, 333 | ExitGuid, 334 | &ExitEvent); 335 | 336 | // Return if event create failed (yet again) 337 | if (EFI_ERROR(status)) 338 | { 339 | Print(L"Can't create event (ExitBootServicesEvent): %d\n", status); 340 | return status; 341 | } 342 | 343 | // Hook SetVariable (should not fail) 344 | oSetVariable = (EFI_SET_VARIABLE)SetServicePointer(&RT->Hdr, (VOID**)&RT->SetVariable, (VOID**)&HookedSetVariable); 345 | 346 | // Hook all the other runtime services functions 347 | oGetTime = (EFI_GET_TIME)SetServicePointer(&RT->Hdr, (VOID**)&RT->GetTime, (VOID**)&HookedGetTime); 348 | oSetTime = (EFI_SET_TIME)SetServicePointer(&RT->Hdr, (VOID**)&RT->SetTime, (VOID**)&HookedSetTime); 349 | oGetWakeupTime = (EFI_SET_TIME)SetServicePointer(&RT->Hdr, (VOID**)&RT->GetWakeupTime, (VOID**)&HookedGetWakeupTime); 350 | oSetWakeupTime = (EFI_SET_WAKEUP_TIME)SetServicePointer(&RT->Hdr, (VOID**)&RT->SetWakeupTime, (VOID**)&HookedSetWakeupTime); 351 | oSetVirtualAddressMap = (EFI_SET_VIRTUAL_ADDRESS_MAP)SetServicePointer(&RT->Hdr, (VOID**)&RT->SetVirtualAddressMap, (VOID**)&HookedSetVirtualAddressMap); 352 | oConvertPointer = (EFI_CONVERT_POINTER)SetServicePointer(&RT->Hdr, (VOID**)&RT->ConvertPointer, (VOID**)&HookedConvertPointer); 353 | oGetVariable = (EFI_GET_VARIABLE)SetServicePointer(&RT->Hdr, (VOID**)&RT->GetVariable, (VOID**)&HookedGetVariable); 354 | oGetNextVariableName = (EFI_GET_NEXT_VARIABLE_NAME)SetServicePointer(&RT->Hdr, (VOID**)&RT->GetNextVariableName, (VOID**)&HookedGetNextVariableName); 355 | //oSetVariable = (EFI_SET_VARIABLE)SetServicePointer(&RT->Hdr, (VOID**)&RT->SetVariable, (VOID**)&HookedSetVariable); 356 | oGetNextHighMonotonicCount = (EFI_GET_NEXT_HIGH_MONO_COUNT)SetServicePointer(&RT->Hdr, (VOID**)&RT->GetNextHighMonotonicCount, (VOID**)&HookedGetNextHighMonotonicCount); 357 | oResetSystem = (EFI_RESET_SYSTEM)SetServicePointer(&RT->Hdr, (VOID**)&RT->ResetSystem, (VOID**)&HookedResetSystem); 358 | oUpdateCapsule = (EFI_UPDATE_CAPSULE)SetServicePointer(&RT->Hdr, (VOID**)&RT->UpdateCapsule, (VOID**)&HookedUpdateCapsule); 359 | oQueryCapsuleCapabilities = (EFI_QUERY_CAPSULE_CAPABILITIES)SetServicePointer(&RT->Hdr, (VOID**)&RT->QueryCapsuleCapabilities, (VOID**)&HookedQueryCapsuleCapabilities); 360 | oQueryVariableInfo = (EFI_QUERY_VARIABLE_INFO)SetServicePointer(&RT->Hdr, (VOID**)&RT->QueryVariableInfo, (VOID**)&HookedQueryVariableInfo); 361 | 362 | // Print confirmation text 363 | Print(L"efi-memory (build on: %a in: %a)\n", __DATE__, __TIME__); 364 | Print(L"https://github.com/SamuelTulach/efi-memory\n"); 365 | 366 | return EFI_SUCCESS; 367 | } 368 | --------------------------------------------------------------------------------