From 3aa5485d939aa43174a557704b6d75b9f88e512e Mon Sep 17 00:00:00 2001 From: sn99 <42946112+sn99@users.noreply.github.com> Date: Wed, 9 Nov 2022 21:59:55 +0530 Subject: [PATCH] A few changes (#2) see CHANGELOG v0.5.0 --- CHANGELOG.md | 7 +++ Cargo.toml | 13 ++--- README.md | 4 +- minifilter/snFilter/snFilter.cpp | 6 +-- src/bin/minifilter.rs | 2 +- src/driver_comm.rs | 89 ++++++++++++++++++++------------ src/lib.rs | 26 +++++----- src/shared_def.rs | 23 +++++---- 8 files changed, 100 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c64b00f..a8f77a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v0.5.0 + +- Replace `ZwClose` with `FltClose` in minifilter to solve potential memory leak +- Remove unused dependencies and add categories to `Cargo.toml` +- Vastly improve documentation +- Refactor code to be more readable and conscience + # v0.4.0 - Improve performance even further diff --git a/Cargo.toml b/Cargo.toml index d243031..0c151b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,29 +1,24 @@ [package] name = "fsfilter-rs" -version = "0.4.0" +version = "0.5.0" edition = "2021" authors = ["sn99 "] description = "A rust library to monitor filesystem and more in windows" -repository = "https://github.com/sn99/fsfilter-rs" +repository = "https://github.com/SubconsciousCompute/fsfilter-rs" +homepage = "https://github.com/SubconsciousCompute/fsfilter-rs" license = "MIT" readme = "README.md" keywords = ["filesystem", "driver", "windows", "minifilter", "syscalls"] +categories = ["development-tools", "os::windows-apis", "filesystem", "api-bindings"] documentation = "https://docs.rs/fsfilter-rs" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] sysinfo = "0.26.4" widestring = "1.0.1" -serde_json = "1.0.68" serde = { version = "1.0.130", features = ["derive"] } -num = "0.4" num-derive = "0.3" num-traits = "0.2.14" -strum = "0.24.1" -strum_macros = "0.24.3" wchar = "0.11.0" -kodama = "0.2.3" [dependencies.windows] version = "0.43.0" diff --git a/README.md b/README.md index 16ac3b4..9447b36 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,9 @@ You can also build using [EWDK](EWDKbuild.md) if you don't want to install Visua ### RUNNING EXAMPLE Use `cargo run --bin minifilter --release` to run the example application or just [run the `.exe` provided in -releases](https://github.com/SubconsciousCompute/fsfilter-rs/releases/latest/download/minifilter.exe). +releases](https://github.com/SubconsciousCompute/fsfilter-rs/releases/latest/download/minifilter.exe) as administrator ( +for some reason the new default terminal on 2H22 is very, very slow +). The program starts to print the `IOMessage` which is defined like: diff --git a/minifilter/snFilter/snFilter.cpp b/minifilter/snFilter/snFilter.cpp index de53c07..56848b9 100644 --- a/minifilter/snFilter/snFilter.cpp +++ b/minifilter/snFilter/snFilter.cpp @@ -1186,7 +1186,7 @@ VOID AddRemProcessRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create) if (!NT_SUCCESS(hr)) { DbgPrint("!!! snFilter: Failed to open process: %#010x.\n", hr); - hr = ZwClose(procHandleParent); + hr = FltClose(procHandleParent); if (!NT_SUCCESS(hr)) { DbgPrint("!!! snFilter: Failed to close process: %#010x.\n", hr); @@ -1212,13 +1212,13 @@ VOID AddRemProcessRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create) DbgPrint("!!! snFilter: New Process, parent: %wZ. Pid: %d\n", parentName, (ULONG)(ULONG_PTR)ParentId); - hr = ZwClose(procHandleParent); + hr = FltClose(procHandleParent); if (!NT_SUCCESS(hr)) { DbgPrint("!!! snFilter: Failed to close process: %#010x.\n", hr); return; } - hr = ZwClose(procHandleProcess); + hr = FltClose(procHandleProcess); if (!NT_SUCCESS(hr)) { DbgPrint("!!! snFilter: Failed to close process: %#010x.\n", hr); diff --git a/src/bin/minifilter.rs b/src/bin/minifilter.rs index 7ed2510..5b72290 100644 --- a/src/bin/minifilter.rs +++ b/src/bin/minifilter.rs @@ -41,7 +41,7 @@ fn main() { loop { if let Ok(mut io_message) = rx_iomsgs.recv() { io_message.exepath(); - write!(lock, "{:?}", io_message); + write!(lock, "{io_message:?}"); } } } diff --git a/src/driver_comm.rs b/src/driver_comm.rs index cc8bf75..b1ac77e 100644 --- a/src/driver_comm.rs +++ b/src/driver_comm.rs @@ -1,8 +1,7 @@ //! Low-level communication with the minifilter. -use core::ffi::c_void; use std::mem; -use std::os::raw::*; +use std::os::raw::{c_ulong, c_ulonglong}; use std::ptr; use sysinfo::{get_current_pid, Pid, PidExt}; @@ -19,6 +18,7 @@ use crate::driver_comm::DriveType::{ DriveCDRom, DriveFixed, DriveNoRootDir, DriveRamDisk, DriveRemote, DriveRemovable, DriveUnknown, }; use crate::driver_comm::IrpMajorOp::{IrpCreate, IrpNone, IrpRead, IrpSetInfo, IrpWrite}; +use crate::shared_def; use crate::shared_def::ReplyIrp; type BufPath = [wchar_t; 520]; @@ -72,14 +72,20 @@ impl Driver { } /// The user-mode running app (this one) has to register itself to the driver. + /// + /// # Panics + /// This fn panics if it is unable to get the current pid. + /// + /// # Errors + /// This fn returns an error if it is unable to register itself to the minifilter. #[inline] pub fn driver_set_app_pid(&self) -> Result<(), windows::core::Error> { - let buf = Driver::string_to_commessage_buffer(r"\Device\harddiskVolume"); + let buf = Self::string_to_commessage_buffer(r"\Device\harddiskVolume"); let mut get_irp_msg: DriverComMessage = DriverComMessage { r#type: DriverComMessageType::SetPid as c_ulong, pid: get_current_pid().unwrap().as_u32() as c_ulong, - gid: 140713315094899, + gid: 140_713_315_094_899, path: buf, //wch!("\0"), }; let mut tmp: u32 = 0; @@ -87,39 +93,49 @@ impl Driver { unsafe { FilterSendMessage( self.handle, - ptr::addr_of_mut!(get_irp_msg) as *mut c_void, + ptr::addr_of_mut!(get_irp_msg).cast::(), mem::size_of::() as c_ulong, None, 0, - &mut tmp as *mut u32, + std::ptr::addr_of_mut!(tmp), ) } } - /// Try to open a com canal with the minifilter before this app is registered. This fn can fail - /// is the minifilter is unreachable: + /// Try to open a com canal with the minifilter before this app is registered. + /// + /// # Panics + /// This function will panic if the minifilter port has any nul value (except the last one) + /// in it's name. + /// + /// # Errors + /// This fn can fail is the minifilter is unreachable: /// /// * if it is not started (try `sc start snFilter` first /// * if a connection is already established: it can accepts only one at a time. /// - /// In that case the Error is raised by the OS (windows::Error) and is generally readable. + /// In that case the Error is raised by the OS (`windows::Error`) and is generally readable. #[inline] - pub fn open_kernel_driver_com() -> Result { - let _com_port_name = U16CString::from_str("\\snFilter").unwrap().into_raw(); - let _handle; + pub fn open_kernel_driver_com() -> Result { + let com_port_name = U16CString::from_str("\\snFilter").unwrap().into_raw(); + let handle; unsafe { - _handle = FilterConnectCommunicationPort(PCWSTR(_com_port_name), 0, None, 0, None)? + handle = FilterConnectCommunicationPort(PCWSTR(com_port_name), 0, None, 0, None)?; } - let res = Driver { handle: _handle }; + let res = Self { handle }; Ok(res) } - /// Ask the driver for a [ReplyIrp], if any. This is a low-level function and the returned object + /// Ask the driver for a [`ReplyIrp`], if any. This is a low-level function and the returned object /// uses C pointers. Managing C pointers requires a special care, because of the Rust timelines. - /// [ReplyIrp] is optional since the minifilter returns null if there is no new activity. + /// [`ReplyIrp`] is optional since the minifilter returns null if there is no new activity. + /// + /// # Panics + /// This fn panics if it is unable to get the current pid or cannot get driver message from the + /// minifilter. #[inline] pub fn get_irp(&self, vecnew: &mut Vec) -> Option { - let mut get_irp_msg = Driver::build_irp_msg( + let mut get_irp_msg = Self::build_irp_msg( DriverComMessageType::GetOps, get_current_pid().unwrap(), 0, @@ -130,11 +146,11 @@ impl Driver { unsafe { FilterSendMessage( self.handle, - ptr::addr_of_mut!(get_irp_msg) as *mut c_void, + ptr::addr_of_mut!(get_irp_msg).cast::(), mem::size_of::() as c_ulong, - Option::from(vecnew.as_ptr() as *mut c_void), + Option::from(vecnew.as_mut_ptr().cast::()), 65536_u32, - ptr::addr_of_mut!(tmp) as *mut u32, + ptr::addr_of_mut!(tmp).cast::(), ) .expect("Cannot get driver message from driver"); } @@ -142,7 +158,8 @@ impl Driver { if tmp != 0 { let reply_irp: ReplyIrp; unsafe { - reply_irp = std::ptr::read_unaligned(vecnew.as_ptr() as *const ReplyIrp); + reply_irp = + std::ptr::read_unaligned(vecnew.as_ptr().cast::()); } return Some(reply_irp); } @@ -150,7 +167,7 @@ impl Driver { } /// Ask the minifilter to kill all pids related to the given *gid*. Pids are killed in driver-mode - /// by calls to NtClose. + /// by calls to `NtClose`. #[inline] pub fn try_kill(&self, gid: c_ulonglong) -> Result { let mut killmsg = DriverComMessage { @@ -165,11 +182,11 @@ impl Driver { unsafe { FilterSendMessage( self.handle, - ptr::addr_of_mut!(killmsg) as *mut c_void, + ptr::addr_of_mut!(killmsg).cast::(), mem::size_of::() as c_ulong, - Option::from(ptr::addr_of_mut!(res) as *mut c_void), + Option::from(ptr::addr_of_mut!(res).cast::()), 4_u32, - ptr::addr_of_mut!(res_size) as *mut u32, + ptr::addr_of_mut!(res_size).cast::(), )?; } @@ -178,7 +195,7 @@ impl Driver { #[inline] fn string_to_commessage_buffer(bufstr: &str) -> BufPath { - let temp = U16CString::from_str(&bufstr).unwrap(); + let temp = U16CString::from_str(bufstr).unwrap(); let mut buf: BufPath = [0; 520]; for (i, c) in temp.as_slice_with_nul().iter().enumerate() { buf[i] = *c as wchar_t; @@ -198,7 +215,7 @@ impl Driver { r#type: commsgtype as c_ulong, // SetPid pid: pid.as_u32() as c_ulong, gid, - path: Driver::string_to_commessage_buffer(path), + path: Self::string_to_commessage_buffer(path), } } } @@ -223,14 +240,14 @@ pub enum IrpMajorOp { } impl IrpMajorOp { - pub fn from_byte(b: u8) -> IrpMajorOp { + #[inline] + pub fn from_byte(b: u8) -> Self { match b { - 0 => IrpNone, + // 0 => IrpNone, 1 => IrpRead, 2 => IrpWrite, 3 => IrpSetInfo, - 4 => IrpCreate, - 5 => IrpCreate, + 4 | 5 => IrpCreate, _ => IrpNone, } } @@ -257,18 +274,22 @@ pub enum DriveType { } impl DriveType { + /// Determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive. + /// + /// # Panics + /// Will panic if drive path is invalid. #[inline] - pub fn from_filepath(filepath: String) -> DriveType { + pub fn from_filepath(filepath: &str) -> Self { let mut drive_type = 1u32; if !filepath.is_empty() { - let drive_path = &filepath[..(filepath.find('\\').unwrap() + 1)]; + let drive_path = &filepath[..=filepath.find('\\').unwrap()]; unsafe { drive_type = GetDriveTypeA(PCSTR(String::from(drive_path).as_ptr())); } } match drive_type { 0 => DriveUnknown, - 1 => DriveNoRootDir, + // 1 => DriveNoRootDir, 2 => DriveRemovable, 3 => DriveFixed, 4 => DriveRemote, diff --git a/src/lib.rs b/src/lib.rs index 83cf7be..18c2f0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! # minifilter-rs //! -//! Checkout the [README](https://github.com/sn99/fsfilter-rs/blob/master/README.md) too at github. +//! Checkout the [README](https://github.com/SubconsciousCompute/fsfilter-rs/blob/master/README.md) too at github. //! //! **Use `cargo doc --no-deps --document-private-items --open` to read Documentation** //! @@ -9,14 +9,14 @@ //!
//! Table of Contents //! -//! - [Minifilter Driver](https://!github.com/sn99/fsfilter-rs#minifilter-driver) -//! - [Building Driver](https://!github.com/sn99/fsfilter-rs#building-driver) -//! - [Installing Driver](https://!github.com/sn99/fsfilter-rs#building-driver) -//! - [Loading/Removing Driver](https://!github.com/sn99/fsfilter-rs#loadingremoving-driver) -//! - [Rust Application](https://!github.com/sn99/fsfilter-rs#rust-application) -//! - [Building Rust App](https://!github.com/sn99/fsfilter-rs#building-rust-app) -//! - [Running Rust App](https://!github.com/sn99/fsfilter-rs#running-rust-app) -//! - [What and the How](https://!github.com/sn99/fsfilter-rs#what-and-the-how) +//! - [Minifilter Driver](https://!github.com/SubconsciousCompute/fsfilter-rs#minifilter-driver) +//! - [Building Driver](https://!github.com/SubconsciousCompute/fsfilter-rs#building-driver) +//! - [Installing Driver](https://!github.com/SubconsciousCompute/fsfilter-rs#building-driver) +//! - [Loading/Removing Driver](https://!github.com/SubconsciousCompute/fsfilter-rs#loadingremoving-driver) +//! - [Rust Application](https://!github.com/SubconsciousCompute/fsfilter-rs#rust-application) +//! - [Building Rust App](https://!github.com/SubconsciousCompute/fsfilter-rs#building-rust-app) +//! - [Running Rust App](https://!github.com/SubconsciousCompute/fsfilter-rs#running-rust-app) +//! - [What and the How](https://!github.com/SubconsciousCompute/fsfilter-rs#what-and-the-how) //! //!
//! @@ -74,7 +74,7 @@ //! Filter Name Num Instances Altitude Frame //! ------------------------------ ------------- ------------ ----- //! bindflt 1 409800 0 -//! snFilter 4 378781 0 //! our minifilter driver +//! snFilter 4 378781 0 //our minifilter driver //! WdFilter 5 328010 0 //! storqosflt 0 244000 0 //! wcifs 0 189900 0 @@ -119,19 +119,19 @@ //! ``` //! //! We end the process using `ctrl + c` in the example video: -//! ![video](https://!github.com/sn99/fsfilter-rs/readme_resources/example.gif) +//! ![video](https://!github.com/SubconsciousCompute/fsfilter-rs/readme_resources/example.gif) //! //! #### NOTE: //! //! - Might fail if not ran with administrative privileges -//! - You need to [load and start the driver]((https://!github.com/sn99/fsfilter-rs#loadingremoving-driver)) before running +//! - You need to [load and start the driver]((https://!github.com/SubconsciousCompute/fsfilter-rs#loadingremoving-driver)) before running //! the program or else it will error out //! //! ## What and the How //! //! We basically share definition between the mini-filter and Rust using `#[repr(C)]` //! -//! ![shared_def](https://!github.com/sn99/fsfilter-rs/readme_resources/shared_def.png) +//! ![`shared_def`](https://!github.com/SubconsciousCompute/fsfilter-rs/readme_resources/shared_def.png) //! //! We use [channels](https://!doc.rust-lang.org/std/sync/mpsc/fn.channel.html) to process //! all [IRPs](https://!docs.microsoft.com/en-us/windows-hardware/drivers/ifs/irps-are-different-from-fast-i-o). diff --git a/src/shared_def.rs b/src/shared_def.rs index e484cef..e886cc4 100644 --- a/src/shared_def.rs +++ b/src/shared_def.rs @@ -40,9 +40,9 @@ pub enum FileLocationInfo { } /// Low-level C-like object to communicate with the minifilter. -/// The minifilter yields ReplyIrp objects (retrieved by [`get_irp`](crate::driver_comm::Driver::get_irp) to +/// The minifilter yields `ReplyIrp` objects (retrieved by [`get_irp`](crate::driver_comm::Driver::get_irp) to /// manage the fixed size of the *data buffer. -/// In other words, a ReplyIrp is a collection of [`CDriverMsg`] with a capped size. +/// In other words, a `ReplyIrp` is a collection of [`CDriverMsg`] with a capped size. #[derive(Debug, Copy, Clone)] #[repr(C)] pub struct ReplyIrp { @@ -55,7 +55,7 @@ pub struct ReplyIrp { } impl ReplyIrp { - /// Iterate through ```self.data``` and returns the collection of [`CDriverMsg`] + /// Iterate through `self.data` and returns the collection of [`CDriverMsg`] #[inline] fn unpack_drivermsg(&self) -> Vec<&CDriverMsg> { let mut res = vec![]; @@ -102,7 +102,7 @@ impl UnicodeString { } */ - /// Get the file path from the UnicodeString path and the extension returned by the driver. + /// Get the file path from the `UnicodeString` path and the extension returned by the driver. #[inline] pub fn to_string_ext(&self, extension: [wchar_t; 12]) -> String { unsafe { @@ -222,9 +222,10 @@ pub struct IOMessage { } impl IOMessage { + /// Make a new [`IOMessage`] from a received [`CDriverMsg`] #[inline] - pub fn from(c_drivermsg: &CDriverMsg) -> IOMessage { - IOMessage { + pub fn from(c_drivermsg: &CDriverMsg) -> Self { + Self { extension: c_drivermsg.extension, file_id_vsn: c_drivermsg.file_id.VolumeSerialNumber, file_id_id: c_drivermsg.file_id.FileId.Identifier, @@ -249,9 +250,11 @@ impl IOMessage { } } + /// Opens an existing local process object to retrieve the name of the executable file for the + /// specified process. #[inline] pub fn exepath(&mut self) { - let pid = self.pid as u32; + let pid = self.pid; unsafe { let r_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); if let Ok(handle) = r_handle { @@ -288,9 +291,10 @@ pub struct RuntimeFeatures { } impl RuntimeFeatures { + /// Make a new [`RuntimeFeatures`] #[inline] - pub fn new() -> RuntimeFeatures { - RuntimeFeatures { + pub fn new() -> Self { + Self { exepath: PathBuf::new(), exe_still_exists: true, } @@ -336,6 +340,7 @@ pub struct CDriverMsgs<'a> { } impl CDriverMsgs<'_> { + /// Make a new [`CDriverMsgs`] from a received [`ReplyIrp`] #[inline] pub fn new(irp: &ReplyIrp) -> CDriverMsgs { CDriverMsgs {