├── .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 |
--------------------------------------------------------------------------------