From dc45399a3ce7584cb0ff4c176487cd41a1517494 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Mon, 18 Nov 2024 15:21:53 +0100 Subject: [PATCH] Mmk --- src/bindings.toml | 3 +- src/lib.rs | 70 +++++++++++++++++++++++++++++++++------------ src/win_bindings.rs | 33 ++++++++++++++------- 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/src/bindings.toml b/src/bindings.toml index e9d457d..236f757 100644 --- a/src/bindings.toml +++ b/src/bindings.toml @@ -1,8 +1,9 @@ output = "win_bindings.rs" binds = [ "MAX_PATH", + "NtClose", + "NtOpenProcess", "NtQueryInformationProcess", - "OpenProcess", "ProcessBasicInformation", "ProcessImageFileName", "PROCESS_BASIC_INFORMATION", diff --git a/src/lib.rs b/src/lib.rs index 2f78964..a33f640 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -271,69 +271,103 @@ pub fn is_powershell_parent() -> bool { use std::os::windows::ffi::OsStringExt as _; use win_bindings::*; - let mut pid = Some(-1 /* NtCurrentProcess */); + struct NtHandle { + handle: isize, + } + + impl Drop for NtHandle { + fn drop(&mut self) { + if self.handle != -1 { + unsafe { + nt_close(self.handle); + } + } + } + } + + let mut handle = Some(NtHandle { handle: -1 }); unsafe { let reset = |fname: &mut [u16]| { let ustr = &mut *fname.as_mut_ptr().cast::(); ustr.length = 0; ustr.maximum_length = MaxPath as _; - ustr.buffer = fname - .as_mut_ptr() - .byte_offset(std::mem::size_of::() as _); }; // The API for this is extremely irritating, the struct and string buffer // need to be the same :/ let mut file_name = [0u16; MaxPath as usize + std::mem::size_of::() / 2]; - while let Some(ppid) = pid { + while let Some(ph) = handle { let mut basic_info = std::mem::MaybeUninit::::uninit(); let mut length = 0; if dbg!(nt_query_information_process( - ppid, + ph.handle, Processinfoclass::ProcessBasicInformation, basic_info.as_mut_ptr().cast(), std::mem::size_of::() as _, &mut length, )) != StatusSuccess { - return false; + break; } if length != std::mem::size_of::() as u32 { - return false; + break; } let basic_info = basic_info.assume_init(); reset(&mut file_name); + let ppid = basic_info.inherited_from_unique_process_id as isize; + + if ppid == 0 || ppid == -1 { + break; + } + + let mut parent_handle = -1; + let obj_attr = std::mem::zeroed(); + let client_id = ClientId { + unique_process: ppid, + unique_thread: 0, + }; + if dbg!(nt_open_process( + &mut parent_handle, + ProcessAccessRights::ProcessQueryInformation, + &obj_attr, + &client_id + )) != StatusSuccess + { + break; + } + + handle = Some(NtHandle { + handle: parent_handle, + }); + if dbg!(nt_query_information_process( - basic_info.inherited_from_unique_process_id as _, + parent_handle, Processinfoclass::ProcessImageFileName, file_name.as_mut_ptr().cast(), (file_name.len() * 2) as _, &mut length, )) != StatusSuccess { - return false; + break; } let ustr = &*file_name.as_ptr().cast::(); - let os = std::ffi::OsString::from_wide( - &file_name[std::mem::size_of::() * 2 - ..std::mem::size_of::() * 2 + ustr.length as usize], - ); + let os = std::ffi::OsString::from_wide(std::slice::from_raw_parts( + ustr.buffer, + (ustr.length >> 1) as usize, + )); let path = os.to_string_lossy(); - dbg!(&path); + eprintln!("{path}"); let p = std::path::Path::new(path.as_ref()); if p.file_stem() == Some(std::ffi::OsStr::new("pwsh")) { return true; } - - pid = (basic_info.inherited_from_unique_process_id != 0) - .then_some(basic_info.inherited_from_unique_process_id as isize); } false diff --git a/src/win_bindings.rs b/src/win_bindings.rs index 78fb2ee..eab6f1d 100644 --- a/src/win_bindings.rs +++ b/src/win_bindings.rs @@ -5,17 +5,17 @@ non_camel_case_types, clippy::upper_case_acronyms )] -#[link(name = "kernel32", kind = "raw-dylib")] -extern "system" { - #[link_name = "OpenProcess"] - pub fn open_process( - desired_access: ProcessAccessRights::Enum, - inherit_handle: Bool, - process_id: u32, - ) -> Handle; -} #[link(name = "ntdll", kind = "raw-dylib")] extern "system" { + #[link_name = "NtClose"] + pub fn nt_close(handle: Handle) -> Ntstatus; + #[link_name = "NtOpenProcess"] + pub fn nt_open_process( + process_handle: *mut Handle, + desired_access: u32, + object_attributes: *const ObjectAttributes, + client_id: *const ClientId, + ) -> Ntstatus; #[link_name = "NtQueryInformationProcess"] pub fn nt_query_information_process( process_handle: Handle, @@ -26,7 +26,11 @@ extern "system" { ) -> Ntstatus; } pub const MaxPath: u32 = 260; -pub type Bool = i32; +#[repr(C)] +pub struct ClientId { + pub unique_process: Handle, + pub unique_thread: Handle, +} pub type Handle = isize; #[repr(C)] pub struct ListEntry { @@ -36,6 +40,15 @@ pub struct ListEntry { pub type Ntstatus = i32; pub const StatusSuccess: Ntstatus = 0; #[repr(C)] +pub struct ObjectAttributes { + pub length: u32, + pub root_directory: Handle, + pub object_name: *mut UnicodeString, + pub attributes: u32, + pub security_descriptor: *mut ::core::ffi::c_void, + pub security_quality_of_service: *mut ::core::ffi::c_void, +} +#[repr(C)] pub struct Peb { pub reserved1: [u8; 2], pub being_debugged: u8,