Skip to content

Commit

Permalink
feat: replace windows dependency with windows-sys
Browse files Browse the repository at this point in the history
  • Loading branch information
vthib committed Apr 14, 2024
1 parent a3fe0f3 commit 3b9a003
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 94 deletions.
55 changes: 1 addition & 54 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions boreal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ authenticode = ["dep:authenticode-parser", "dep:hex"]
memmap = ["dep:memmap2"]

# Adds APIs to scan process memories.
process = ["dep:libc", "dep:windows", "dep:mach2"]
process = ["dep:libc", "dep:windows-sys", "dep:mach2"]

# Enables computation of statistics during scanning.
profiling = []
Expand Down Expand Up @@ -76,7 +76,7 @@ libc = { version = "0.2", optional = true }
mach2 = { version = "0.4", optional = true }

[target.'cfg(windows)'.dependencies]
windows = { version = "0.56", optional = true, features = [
windows-sys = { version = "0.52", optional = true, features = [
"Win32_Foundation",
# LookupPrivilegeValue, AdjustTokenPrivileges
"Win32_Security",
Expand Down
89 changes: 60 additions & 29 deletions boreal/src/scanner/process/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, OwnedHandle};

use windows::Win32::Foundation::{ERROR_INVALID_PARAMETER, HANDLE, LUID};
use windows::Win32::Security::{
use windows_sys::Win32::Foundation::{ERROR_INVALID_PARAMETER, HANDLE, LUID};
use windows_sys::Win32::Security::{
AdjustTokenPrivileges, LookupPrivilegeValueW, LUID_AND_ATTRIBUTES, SE_DEBUG_NAME,
SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, TOKEN_PRIVILEGES,
};
use windows::Win32::System::Diagnostics::Debug::ReadProcessMemory;
use windows::Win32::System::Memory::{
use windows_sys::Win32::System::Diagnostics::Debug::ReadProcessMemory;
use windows_sys::Win32::System::Memory::{
VirtualQueryEx, MEMORY_BASIC_INFORMATION, MEM_COMMIT, PAGE_NOACCESS,
};
use windows::Win32::System::Threading::{
use windows_sys::Win32::System::Threading::{
GetCurrentProcess, OpenProcess, OpenProcessToken, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ,
};

Expand All @@ -33,24 +33,27 @@ pub fn process_memory(pid: u32) -> Result<Box<dyn FragmentedMemory>, ScanError>
// PROCESS_QUERY_INFORMATION for VirtualQueryEx
// PROCESS_VM_READ for ReadProcessMemory
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
false,
0,
pid,
)
};
let handle = match res {
Ok(handle) => {
// Safety:
// - The handle is valid since the call to OpenProcess succeeded
// - The handle must be closed with `CloseHandle`.
unsafe { OwnedHandle::from_raw_handle(handle.0 as _) }
}
Err(err) if err.code() == ERROR_INVALID_PARAMETER.into() => {
return Err(ScanError::UnknownProcess);
}
Err(err) => {
return Err(ScanError::CannotListProcessRegions(err.into()));
}
};

if res == 0 {
let err = std::io::Error::last_os_error();
return Err(
#[allow(clippy::cast_possible_wrap)]
if err.raw_os_error() == Some(ERROR_INVALID_PARAMETER as _) {
ScanError::UnknownProcess
} else {
ScanError::CannotListProcessRegions(err)
},
);
}

// Safety:
// - The handle is valid since the call to OpenProcess succeeded
// - The handle must be closed with `CloseHandle`.
let handle = unsafe { OwnedHandle::from_raw_handle(res as _) };

Ok(Box::new(WindowsProcessMemory {
handle,
Expand All @@ -59,7 +62,7 @@ pub fn process_memory(pid: u32) -> Result<Box<dyn FragmentedMemory>, ScanError>
}))
}

fn enable_se_debug_privilege() -> Result<(), windows::core::Error> {
fn enable_se_debug_privilege() -> Result<(), std::io::Error> {
let mut self_token = HANDLE::default();

// Safety: this is always safe to call.
Expand All @@ -68,12 +71,28 @@ fn enable_se_debug_privilege() -> Result<(), windows::core::Error> {
// - handle is valid and has PROCESS_QUERY_LIMITED_INFORMATION
// permission since it was retrieve with GetCurrentProcess.
// - TOKEN_ADJUST_PRIVILEGES is a valid access to ask for.
unsafe { OpenProcessToken(self_handle, TOKEN_ADJUST_PRIVILEGES, &mut self_token) }?;
let res = unsafe { OpenProcessToken(self_handle, TOKEN_ADJUST_PRIVILEGES, &mut self_token) };
if res == 0 {
return Err(std::io::Error::last_os_error());
}

let mut debug_privilege_luid = LUID {
LowPart: 0,
HighPart: 0,
};

let mut debug_privilege_luid = LUID::default();
// Safety:
// - SE_DEBUG_NAME is a wide string ending with a null byte.
unsafe { LookupPrivilegeValueW(None, SE_DEBUG_NAME, &mut debug_privilege_luid) }?;
let res = unsafe {
LookupPrivilegeValueW(
std::ptr::null_mut(),
SE_DEBUG_NAME,
&mut debug_privilege_luid,
)
};
if res == 0 {
return Err(std::io::Error::last_os_error());
}

let cfg = TOKEN_PRIVILEGES {
PrivilegeCount: 1,
Expand All @@ -86,7 +105,19 @@ fn enable_se_debug_privilege() -> Result<(), windows::core::Error> {
// - token is valid and opened with TOKEN_ADJUST_PRIVILEGES
// - NewState is well-formed, count is 1 and the Privileges array has one element
// - Rest of arguments are optional
unsafe { AdjustTokenPrivileges(self_token, false, Some(&cfg), 0, None, None) }?;
let res = unsafe {
AdjustTokenPrivileges(
self_token,
0,
&cfg,
0,
std::ptr::null_mut(),
std::ptr::null_mut(),
)
};
if res == 0 {
return Err(std::io::Error::last_os_error());
}

Ok(())
}
Expand Down Expand Up @@ -135,7 +166,7 @@ fn query_next_region(handle: BorrowedHandle, mut next_addr: usize) -> Option<Reg
let res = unsafe {
VirtualQueryEx(
handle_to_windows_handle(handle.as_handle()),
Some(next_addr as *const c_void),
next_addr as *const c_void,
info.as_mut_ptr(),
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
)
Expand Down Expand Up @@ -190,11 +221,11 @@ impl FragmentedMemory for WindowsProcessMemory {
desc.start as _,
self.buffer.as_mut_ptr().cast(),
self.buffer.len(),
Some(&mut nb_bytes_read),
&mut nb_bytes_read,
)
};

if res.is_err() {
if res == 0 {
return None;
}

Expand All @@ -217,7 +248,7 @@ fn get_chunked_region(desc: RegionDescription, params: &MemoryParams) -> RegionD
}

fn handle_to_windows_handle(handle: BorrowedHandle) -> HANDLE {
HANDLE(handle.as_raw_handle() as _)
handle.as_raw_handle() as HANDLE
}

#[cfg(test)]
Expand Down
12 changes: 3 additions & 9 deletions boreal/tests/it/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,11 @@ fn test_process_permission_denied() {
let err = checker.last_err.unwrap();
match &err {
ScanError::CannotListProcessRegions(err) => {
#[cfg(windows)]
#[cfg(target_os = "macos")]
{
use windows::Win32::Foundation::E_ACCESSDENIED;

assert_eq!(err.raw_os_error(), Some(E_ACCESSDENIED.0 as _), "{:?}", err);
assert_eq!(err.kind(), std::io::ErrorKind::Other, "{:?}", err);
}
#[cfg(target_os = "linux")]
#[cfg(not(target_os = "macos"))]
{
assert_eq!(
err.kind(),
Expand All @@ -73,10 +71,6 @@ fn test_process_permission_denied() {
err
);
}
#[cfg(target_os = "macos")]
{
assert_eq!(err.kind(), std::io::ErrorKind::Other, "{:?}", err);
}
}
err => panic!("Unexpected last err: {err:?}"),
}
Expand Down

0 comments on commit 3b9a003

Please sign in to comment.