diff options
| author | David Lönnhager <david.l@mullvad.net> | 2023-10-17 13:14:12 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-10-20 18:17:24 +0200 |
| commit | 8a5ad4bb07dec0e34985fc5eaa9c40352bc05655 (patch) | |
| tree | b95ea58bc205e0f717e9e4d75bef39d773786f2a /talpid-windows | |
| parent | 5cee95d43bb0cc3654e5558ba02919dbf32d52aa (diff) | |
| download | mullvadvpn-8a5ad4bb07dec0e34985fc5eaa9c40352bc05655.tar.xz mullvadvpn-8a5ad4bb07dec0e34985fc5eaa9c40352bc05655.zip | |
Add process module to talpid-windows
Diffstat (limited to 'talpid-windows')
| -rw-r--r-- | talpid-windows/src/lib.rs | 3 | ||||
| -rw-r--r-- | talpid-windows/src/process.rs | 157 | ||||
| -rw-r--r-- | talpid-windows/src/sync.rs | 24 |
3 files changed, 162 insertions, 22 deletions
diff --git a/talpid-windows/src/lib.rs b/talpid-windows/src/lib.rs index 865c3e8a81..755f6b2e30 100644 --- a/talpid-windows/src/lib.rs +++ b/talpid-windows/src/lib.rs @@ -12,3 +12,6 @@ pub mod net; /// Synchronization pub mod sync; + +/// Processes +pub mod process; diff --git a/talpid-windows/src/process.rs b/talpid-windows/src/process.rs new file mode 100644 index 0000000000..ecddbe09f2 --- /dev/null +++ b/talpid-windows/src/process.rs @@ -0,0 +1,157 @@ +use std::{ + ffi::{c_char, CStr}, + io, mem, +}; +use windows_sys::Win32::{ + Foundation::{CloseHandle, ERROR_NO_MORE_FILES, HANDLE, INVALID_HANDLE_VALUE}, + System::Diagnostics::ToolHelp::{ + CreateToolhelp32Snapshot, Module32First, Module32Next, Process32FirstW, Process32NextW, + MODULEENTRY32, PROCESSENTRY32W, + }, +}; + +/// A snapshot of process modules, threads, and heaps +pub struct ProcessSnapshot { + handle: HANDLE, +} + +impl ProcessSnapshot { + /// Create a new process snapshot using `CreateToolhelp32Snapshot` + pub fn new(flags: u32, process_id: u32) -> io::Result<ProcessSnapshot> { + let snap = unsafe { CreateToolhelp32Snapshot(flags, process_id) }; + + if snap == INVALID_HANDLE_VALUE { + Err(io::Error::last_os_error()) + } else { + Ok(ProcessSnapshot { handle: snap }) + } + } + + /// Return the raw handle + pub fn as_raw(&self) -> HANDLE { + self.handle + } + + /// Return an iterator over the modules in the snapshot + pub fn modules(&self) -> ProcessSnapshotModules<'_> { + let mut entry: MODULEENTRY32 = unsafe { mem::zeroed() }; + entry.dwSize = mem::size_of::<MODULEENTRY32>() as u32; + + ProcessSnapshotModules { + snapshot: self, + iter_started: false, + temp_entry: entry, + } + } + + /// Return an iterator over the processes in the snapshot + pub fn processes(&self) -> ProcessSnapshotEntries<'_> { + let mut entry: PROCESSENTRY32W = unsafe { mem::zeroed() }; + entry.dwSize = mem::size_of::<PROCESSENTRY32W>() as u32; + + ProcessSnapshotEntries { + snapshot: self, + iter_started: false, + temp_entry: entry, + } + } +} + +impl Drop for ProcessSnapshot { + fn drop(&mut self) { + unsafe { + CloseHandle(self.handle); + } + } +} + +/// Description of a snapshot module entry. See `MODULEENTRY32` +pub struct ModuleEntry { + /// Module name + pub name: String, + /// Module base address (in the owning process) + pub base_address: *const u8, + /// Size of the module (in bytes) + pub size: usize, +} + +/// Module iterator for [ProcessSnapshot] +pub struct ProcessSnapshotModules<'a> { + snapshot: &'a ProcessSnapshot, + iter_started: bool, + temp_entry: MODULEENTRY32, +} + +impl Iterator for ProcessSnapshotModules<'_> { + type Item = io::Result<ModuleEntry>; + + fn next(&mut self) -> Option<io::Result<ModuleEntry>> { + if self.iter_started { + if unsafe { Module32Next(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { + let last_error = io::Error::last_os_error(); + + return if last_error.raw_os_error().unwrap() as u32 == ERROR_NO_MORE_FILES { + None + } else { + Some(Err(last_error)) + }; + } + } else { + if unsafe { Module32First(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { + return Some(Err(io::Error::last_os_error())); + } + self.iter_started = true; + } + + let cstr_ref = &self.temp_entry.szModule[0]; + let cstr = unsafe { CStr::from_ptr(cstr_ref as *const u8 as *const c_char) }; + Some(Ok(ModuleEntry { + name: cstr.to_string_lossy().into_owned(), + base_address: self.temp_entry.modBaseAddr, + size: self.temp_entry.modBaseSize as usize, + })) + } +} + +/// Description of a snapshot process entry. See `PROCESSENTRY32W` +pub struct ProcessEntry { + /// Process identifier + pub pid: u32, + /// Process identifier of the parent process + pub parent_pid: u32, +} + +/// Process iterator for [ProcessSnapshot] +pub struct ProcessSnapshotEntries<'a> { + snapshot: &'a ProcessSnapshot, + iter_started: bool, + temp_entry: PROCESSENTRY32W, +} + +impl Iterator for ProcessSnapshotEntries<'_> { + type Item = io::Result<ProcessEntry>; + + fn next(&mut self) -> Option<io::Result<ProcessEntry>> { + if self.iter_started { + if unsafe { Process32NextW(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { + let last_error = io::Error::last_os_error(); + + return if last_error.raw_os_error().unwrap() as u32 == ERROR_NO_MORE_FILES { + None + } else { + Some(Err(last_error)) + }; + } + } else { + if unsafe { Process32FirstW(self.snapshot.as_raw(), &mut self.temp_entry) } == 0 { + return Some(Err(io::Error::last_os_error())); + } + self.iter_started = true; + } + + Some(Ok(ProcessEntry { + pid: self.temp_entry.th32ProcessID, + parent_pid: self.temp_entry.th32ParentProcessID, + })) + } +} diff --git a/talpid-windows/src/sync.rs b/talpid-windows/src/sync.rs index 7b4ed59be3..202c96524d 100644 --- a/talpid-windows/src/sync.rs +++ b/talpid-windows/src/sync.rs @@ -1,7 +1,7 @@ use std::{io, ptr}; use windows_sys::Win32::{ - Foundation::{CloseHandle, DuplicateHandle, BOOL, DUPLICATE_SAME_ACCESS, HANDLE}, - System::Threading::{CreateEventW, GetCurrentProcess, SetEvent}, + Foundation::{CloseHandle, BOOL, HANDLE}, + System::Threading::{CreateEventW, SetEvent}, }; /// Windows event object @@ -39,26 +39,6 @@ impl Event { pub fn as_raw(&self) -> HANDLE { self.0 } - - /// Duplicate the event object with `DuplicateHandle()` - pub fn duplicate(&self) -> io::Result<Event> { - let mut new_event = 0; - let status = unsafe { - DuplicateHandle( - GetCurrentProcess(), - self.0, - GetCurrentProcess(), - &mut new_event, - 0, - 0, - DUPLICATE_SAME_ACCESS, - ) - }; - if status == 0 { - return Err(io::Error::last_os_error()); - } - Ok(Event(new_event)) - } } impl Drop for Event { |
