From cc9f00d29ebb7d6390bec65c649b85a84ba92d5e Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 10:24:27 +0800 Subject: [PATCH 01/27] Add run as user --- crates/nsis-process/src/lib.rs | 2 + crates/nsis-process/src/run_as_user.rs | 162 +++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 crates/nsis-process/src/run_as_user.rs diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 3fd6250..5f3e140 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] +mod run_as_user; + extern crate alloc; use alloc::vec; diff --git a/crates/nsis-process/src/run_as_user.rs b/crates/nsis-process/src/run_as_user.rs new file mode 100644 index 0000000..f9f43ed --- /dev/null +++ b/crates/nsis-process/src/run_as_user.rs @@ -0,0 +1,162 @@ +use core::{mem, ops::Deref, ptr}; + +use alloc::borrow::ToOwned; +use nsis_plugin_api::{encode_utf16, nsis_fn, popstr, push, ONE, ZERO}; +use windows_sys::Win32::{ + Foundation::{ + CloseHandle, GetLastError, LocalFree, ERROR_INSUFFICIENT_BUFFER, FALSE, HANDLE, HLOCAL, + }, + System::{ + Memory::{LocalAlloc, LMEM_FIXED}, + Threading::{ + CreateProcessW, InitializeProcThreadAttributeList, OpenProcess, + UpdateProcThreadAttribute, CREATE_NEW_PROCESS_GROUP, CREATE_UNICODE_ENVIRONMENT, + EXTENDED_STARTUPINFO_PRESENT, PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, + PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, STARTUPINFOEXW, STARTUPINFOW, + }, + }, + UI::WindowsAndMessaging::{GetShellWindow, GetWindowThreadProcessId}, +}; + +/// Run command as unelevated user +/// +/// Needs 2 strings on the stack +/// $1: command +/// $2: arguments +#[nsis_fn] +fn RunAsUser() -> Result<(), Error> { + let command = popstr()?; + let arguments = popstr()?; + if run_as_user(&command, &arguments) { + push(ZERO) + } else { + push(ONE) + } +} + +/// Return true if success +unsafe fn run_as_user(command: &str, arguments: &str) -> bool { + let hwnd = OwnedHandle::new(GetShellWindow()); + if *hwnd == 0 { + return false; + } + let mut proccess_id = 0; + if GetWindowThreadProcessId(*hwnd, &mut proccess_id) != 0 { + return false; + } + let handle = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); + if *handle == 0 { + return false; + } + let mut size = 0; + if !(InitializeProcThreadAttributeList(ptr::null_mut(), 1, 0, &mut size) == FALSE + && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + return false; + } + let Some(attribute_list) = OwnedLocalMemory::new(size) else { + return false; + }; + if InitializeProcThreadAttributeList(*attribute_list, 1, 0, &mut size) == FALSE { + return false; + } + if UpdateProcThreadAttribute( + *attribute_list, + 0, + PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as _, + &*handle as *const _ as _, + mem::size_of::(), + ptr::null_mut(), + ptr::null(), + ) == FALSE + { + return false; + } + let startup_info = STARTUPINFOEXW { + StartupInfo: STARTUPINFOW { + cb: mem::size_of::() as _, + ..mem::zeroed() + }, + lpAttributeList: *attribute_list, + }; + let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; + let mut command_line = command.to_owned(); + command_line.push_str(" "); + command_line.push_str(&arguments); + if CreateProcessW( + encode_utf16(&command).as_ptr(), + encode_utf16(&command_line).as_mut_ptr(), + ptr::null(), + ptr::null(), + FALSE, + CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, + ptr::null(), + ptr::null(), + &startup_info as *const _ as _, + &process_info as *const _ as _, + ) != 0 + { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + } + true +} + +struct OwnedHandle(HANDLE); + +impl OwnedHandle { + fn new(handle: HANDLE) -> Self { + Self(handle) + } +} + +impl Drop for OwnedHandle { + fn drop(&mut self) { + unsafe { CloseHandle(self.0) }; + } +} + +impl Deref for OwnedHandle { + type Target = HANDLE; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +struct OwnedLocalMemory(HLOCAL); + +impl OwnedLocalMemory { + fn new(size: usize) -> Option { + let hlocal = unsafe { LocalAlloc(LMEM_FIXED, size) }; + if hlocal != ptr::null_mut() { + Some(Self(hlocal)) + } else { + None + } + } +} + +impl Drop for OwnedLocalMemory { + fn drop(&mut self) { + unsafe { LocalFree(self.0) }; + } +} + +impl Deref for OwnedLocalMemory { + type Target = HLOCAL; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn spawn_cmd() { + unsafe { run_as_user("cmd", "/c pause") }; + } +} From ad0ac56ec33eb8094a01d544f707d1a971533535 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 10:27:43 +0800 Subject: [PATCH 02/27] Add blog link --- crates/nsis-process/src/run_as_user.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/nsis-process/src/run_as_user.rs b/crates/nsis-process/src/run_as_user.rs index f9f43ed..db9cc40 100644 --- a/crates/nsis-process/src/run_as_user.rs +++ b/crates/nsis-process/src/run_as_user.rs @@ -35,6 +35,8 @@ fn RunAsUser() -> Result<(), Error> { } /// Return true if success +/// +/// Ported from https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443 unsafe fn run_as_user(command: &str, arguments: &str) -> bool { let hwnd = OwnedHandle::new(GetShellWindow()); if *hwnd == 0 { From df183c119583d3971265ca7b99ce3f45e8a195ef Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 10:40:33 +0800 Subject: [PATCH 03/27] Clippy --- crates/nsis-process/src/run_as_user.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/nsis-process/src/run_as_user.rs b/crates/nsis-process/src/run_as_user.rs index db9cc40..0b363da 100644 --- a/crates/nsis-process/src/run_as_user.rs +++ b/crates/nsis-process/src/run_as_user.rs @@ -83,10 +83,10 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { }; let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; let mut command_line = command.to_owned(); - command_line.push_str(" "); - command_line.push_str(&arguments); + command_line.push(' '); + command_line.push_str(arguments); if CreateProcessW( - encode_utf16(&command).as_ptr(), + encode_utf16(command).as_ptr(), encode_utf16(&command_line).as_mut_ptr(), ptr::null(), ptr::null(), @@ -131,10 +131,10 @@ struct OwnedLocalMemory(HLOCAL); impl OwnedLocalMemory { fn new(size: usize) -> Option { let hlocal = unsafe { LocalAlloc(LMEM_FIXED, size) }; - if hlocal != ptr::null_mut() { - Some(Self(hlocal)) - } else { + if hlocal.is_null() { None + } else { + Some(Self(hlocal)) } } } From 0c93df4ee3e7b235ea044d8bd1300cfe65b0edc8 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 10:43:20 +0800 Subject: [PATCH 04/27] Add change file --- .changes/run-as-user.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/run-as-user.md diff --git a/.changes/run-as-user.md b/.changes/run-as-user.md new file mode 100644 index 0000000..939abaa --- /dev/null +++ b/.changes/run-as-user.md @@ -0,0 +1,5 @@ +--- +"nsis_process": "minor" +--- + +Add a new function `RunAsUser` to run command as unelevated user From 0dbb10e2c19384c48ad122c68c91e8b23806cf22 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 11:25:40 +0800 Subject: [PATCH 05/27] Use alloc vec instead of local alloc --- crates/nsis-process/src/run_as_user.rs | 56 +++++--------------------- 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/crates/nsis-process/src/run_as_user.rs b/crates/nsis-process/src/run_as_user.rs index 0b363da..76a2d96 100644 --- a/crates/nsis-process/src/run_as_user.rs +++ b/crates/nsis-process/src/run_as_user.rs @@ -1,19 +1,14 @@ use core::{mem, ops::Deref, ptr}; -use alloc::borrow::ToOwned; +use alloc::{borrow::ToOwned, vec::Vec}; use nsis_plugin_api::{encode_utf16, nsis_fn, popstr, push, ONE, ZERO}; use windows_sys::Win32::{ - Foundation::{ - CloseHandle, GetLastError, LocalFree, ERROR_INSUFFICIENT_BUFFER, FALSE, HANDLE, HLOCAL, - }, - System::{ - Memory::{LocalAlloc, LMEM_FIXED}, - Threading::{ - CreateProcessW, InitializeProcThreadAttributeList, OpenProcess, - UpdateProcThreadAttribute, CREATE_NEW_PROCESS_GROUP, CREATE_UNICODE_ENVIRONMENT, - EXTENDED_STARTUPINFO_PRESENT, PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, - PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, STARTUPINFOEXW, STARTUPINFOW, - }, + Foundation::{CloseHandle, GetLastError, ERROR_INSUFFICIENT_BUFFER, FALSE, HANDLE}, + System::Threading::{ + CreateProcessW, InitializeProcThreadAttributeList, OpenProcess, UpdateProcThreadAttribute, + CREATE_NEW_PROCESS_GROUP, CREATE_UNICODE_ENVIRONMENT, EXTENDED_STARTUPINFO_PRESENT, + PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + STARTUPINFOEXW, STARTUPINFOW, }, UI::WindowsAndMessaging::{GetShellWindow, GetWindowThreadProcessId}, }; @@ -56,14 +51,12 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { { return false; } - let Some(attribute_list) = OwnedLocalMemory::new(size) else { - return false; - }; - if InitializeProcThreadAttributeList(*attribute_list, 1, 0, &mut size) == FALSE { + let mut attribute_list = Vec::with_capacity(size); + if InitializeProcThreadAttributeList(attribute_list.as_mut_ptr(), 1, 0, &mut size) == FALSE { return false; } if UpdateProcThreadAttribute( - *attribute_list, + attribute_list.as_mut_ptr(), 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as _, &*handle as *const _ as _, @@ -79,7 +72,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { cb: mem::size_of::() as _, ..mem::zeroed() }, - lpAttributeList: *attribute_list, + lpAttributeList: attribute_list.as_mut_ptr(), }; let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; let mut command_line = command.to_owned(); @@ -126,33 +119,6 @@ impl Deref for OwnedHandle { } } -struct OwnedLocalMemory(HLOCAL); - -impl OwnedLocalMemory { - fn new(size: usize) -> Option { - let hlocal = unsafe { LocalAlloc(LMEM_FIXED, size) }; - if hlocal.is_null() { - None - } else { - Some(Self(hlocal)) - } - } -} - -impl Drop for OwnedLocalMemory { - fn drop(&mut self) { - unsafe { LocalFree(self.0) }; - } -} - -impl Deref for OwnedLocalMemory { - type Target = HLOCAL; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - #[cfg(test)] mod tests { use super::*; From c5c8526965d881b44c66bda731849775601285a1 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 11:38:23 +0800 Subject: [PATCH 06/27] Move to lib.rs --- crates/nsis-process/src/lib.rs | 127 ++++++++++++++++++++++-- crates/nsis-process/src/run_as_user.rs | 130 ------------------------- crates/nsis-tauri-utils/build.rs | 13 +-- 3 files changed, 124 insertions(+), 146 deletions(-) delete mode 100644 crates/nsis-process/src/run_as_user.rs diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 5f3e140..679ada4 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -1,16 +1,14 @@ #![no_std] -mod run_as_user; - extern crate alloc; -use alloc::vec; use alloc::vec::Vec; -use core::{ffi::c_void, mem, ptr}; +use alloc::{borrow::ToOwned, vec}; +use core::{ffi::c_void, mem, ops::Deref, ptr}; use nsis_plugin_api::*; use windows_sys::Win32::{ - Foundation::{CloseHandle, HANDLE}, + Foundation::{CloseHandle, GetLastError, ERROR_INSUFFICIENT_BUFFER, FALSE, HANDLE}, Security::{EqualSid, GetTokenInformation, TokenUser, TOKEN_QUERY, TOKEN_USER}, System::{ Diagnostics::ToolHelp::{ @@ -18,10 +16,14 @@ use windows_sys::Win32::{ TH32CS_SNAPPROCESS, }, Threading::{ - GetCurrentProcessId, OpenProcess, OpenProcessToken, TerminateProcess, - PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, + CreateProcessW, GetCurrentProcessId, InitializeProcThreadAttributeList, OpenProcess, + OpenProcessToken, TerminateProcess, UpdateProcThreadAttribute, + CREATE_NEW_PROCESS_GROUP, CREATE_UNICODE_ENVIRONMENT, EXTENDED_STARTUPINFO_PRESENT, + PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, PROCESS_QUERY_INFORMATION, + PROCESS_TERMINATE, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, STARTUPINFOEXW, STARTUPINFOW, }, }, + UI::WindowsAndMessaging::{GetShellWindow, GetWindowThreadProcessId}, }; nsis_plugin!(); @@ -120,6 +122,22 @@ fn KillProcessCurrentUser() -> Result<(), Error> { } } +/// Run command as unelevated user +/// +/// Needs 2 strings on the stack +/// $1: command +/// $2: arguments +#[nsis_fn] +fn RunAsUser() -> Result<(), Error> { + let command = popstr()?; + let arguments = popstr()?; + if run_as_user(&command, &arguments) { + push(ZERO) + } else { + push(ONE) + } +} + unsafe fn belongs_to_user(user_sid: *mut c_void, pid: u32) -> bool { let p_sid = get_sid(pid); // Trying to get the sid of a process of another user will give us an "Access Denied" error. @@ -211,6 +229,96 @@ fn get_processes(name: &str) -> Vec { processes } +/// Return true if success +/// +/// Ported from https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443 +unsafe fn run_as_user(command: &str, arguments: &str) -> bool { + let hwnd = OwnedHandle::new(GetShellWindow()); + if *hwnd == 0 { + return false; + } + let mut proccess_id = 0; + if GetWindowThreadProcessId(*hwnd, &mut proccess_id) != 0 { + return false; + } + let handle = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); + if *handle == 0 { + return false; + } + let mut size = 0; + if !(InitializeProcThreadAttributeList(ptr::null_mut(), 1, 0, &mut size) == FALSE + && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + return false; + } + let mut attribute_list = Vec::with_capacity(size); + if InitializeProcThreadAttributeList(attribute_list.as_mut_ptr(), 1, 0, &mut size) == FALSE { + return false; + } + if UpdateProcThreadAttribute( + attribute_list.as_mut_ptr(), + 0, + PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as _, + &*handle as *const _ as _, + mem::size_of::(), + ptr::null_mut(), + ptr::null(), + ) == FALSE + { + return false; + } + let startup_info = STARTUPINFOEXW { + StartupInfo: STARTUPINFOW { + cb: mem::size_of::() as _, + ..mem::zeroed() + }, + lpAttributeList: attribute_list.as_mut_ptr(), + }; + let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; + let mut command_line = command.to_owned(); + command_line.push(' '); + command_line.push_str(arguments); + if CreateProcessW( + encode_utf16(command).as_ptr(), + encode_utf16(&command_line).as_mut_ptr(), + ptr::null(), + ptr::null(), + FALSE, + CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, + ptr::null(), + ptr::null(), + &startup_info as *const _ as _, + &process_info as *const _ as _, + ) != 0 + { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + } + true +} + +struct OwnedHandle(HANDLE); + +impl OwnedHandle { + fn new(handle: HANDLE) -> Self { + Self(handle) + } +} + +impl Drop for OwnedHandle { + fn drop(&mut self) { + unsafe { CloseHandle(self.0) }; + } +} + +impl Deref for OwnedHandle { + type Target = HANDLE; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + #[cfg(test)] mod tests { use super::*; @@ -228,4 +336,9 @@ mod tests { // This will return true on empty iterators so it's basically no-op right now assert!(processes.into_iter().map(kill).all(|b| b)); } + + #[test] + fn spawn_cmd() { + unsafe { run_as_user("cmd", "/c pause") }; + } } diff --git a/crates/nsis-process/src/run_as_user.rs b/crates/nsis-process/src/run_as_user.rs deleted file mode 100644 index 76a2d96..0000000 --- a/crates/nsis-process/src/run_as_user.rs +++ /dev/null @@ -1,130 +0,0 @@ -use core::{mem, ops::Deref, ptr}; - -use alloc::{borrow::ToOwned, vec::Vec}; -use nsis_plugin_api::{encode_utf16, nsis_fn, popstr, push, ONE, ZERO}; -use windows_sys::Win32::{ - Foundation::{CloseHandle, GetLastError, ERROR_INSUFFICIENT_BUFFER, FALSE, HANDLE}, - System::Threading::{ - CreateProcessW, InitializeProcThreadAttributeList, OpenProcess, UpdateProcThreadAttribute, - CREATE_NEW_PROCESS_GROUP, CREATE_UNICODE_ENVIRONMENT, EXTENDED_STARTUPINFO_PRESENT, - PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, - STARTUPINFOEXW, STARTUPINFOW, - }, - UI::WindowsAndMessaging::{GetShellWindow, GetWindowThreadProcessId}, -}; - -/// Run command as unelevated user -/// -/// Needs 2 strings on the stack -/// $1: command -/// $2: arguments -#[nsis_fn] -fn RunAsUser() -> Result<(), Error> { - let command = popstr()?; - let arguments = popstr()?; - if run_as_user(&command, &arguments) { - push(ZERO) - } else { - push(ONE) - } -} - -/// Return true if success -/// -/// Ported from https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443 -unsafe fn run_as_user(command: &str, arguments: &str) -> bool { - let hwnd = OwnedHandle::new(GetShellWindow()); - if *hwnd == 0 { - return false; - } - let mut proccess_id = 0; - if GetWindowThreadProcessId(*hwnd, &mut proccess_id) != 0 { - return false; - } - let handle = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); - if *handle == 0 { - return false; - } - let mut size = 0; - if !(InitializeProcThreadAttributeList(ptr::null_mut(), 1, 0, &mut size) == FALSE - && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - return false; - } - let mut attribute_list = Vec::with_capacity(size); - if InitializeProcThreadAttributeList(attribute_list.as_mut_ptr(), 1, 0, &mut size) == FALSE { - return false; - } - if UpdateProcThreadAttribute( - attribute_list.as_mut_ptr(), - 0, - PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as _, - &*handle as *const _ as _, - mem::size_of::(), - ptr::null_mut(), - ptr::null(), - ) == FALSE - { - return false; - } - let startup_info = STARTUPINFOEXW { - StartupInfo: STARTUPINFOW { - cb: mem::size_of::() as _, - ..mem::zeroed() - }, - lpAttributeList: attribute_list.as_mut_ptr(), - }; - let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; - let mut command_line = command.to_owned(); - command_line.push(' '); - command_line.push_str(arguments); - if CreateProcessW( - encode_utf16(command).as_ptr(), - encode_utf16(&command_line).as_mut_ptr(), - ptr::null(), - ptr::null(), - FALSE, - CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | EXTENDED_STARTUPINFO_PRESENT, - ptr::null(), - ptr::null(), - &startup_info as *const _ as _, - &process_info as *const _ as _, - ) != 0 - { - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - } - true -} - -struct OwnedHandle(HANDLE); - -impl OwnedHandle { - fn new(handle: HANDLE) -> Self { - Self(handle) - } -} - -impl Drop for OwnedHandle { - fn drop(&mut self) { - unsafe { CloseHandle(self.0) }; - } -} - -impl Deref for OwnedHandle { - type Target = HANDLE; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn spawn_cmd() { - unsafe { run_as_user("cmd", "/c pause") }; - } -} diff --git a/crates/nsis-tauri-utils/build.rs b/crates/nsis-tauri-utils/build.rs index 3a7a7cf..8e1449a 100644 --- a/crates/nsis-tauri-utils/build.rs +++ b/crates/nsis-tauri-utils/build.rs @@ -1,3 +1,5 @@ +use std::io::Write; + fn main() { combine_plugins_and_write_to_out_dir(); if std::env::var("CARGO_FEATURE_TEST").as_deref() != Ok("1") { @@ -13,14 +15,7 @@ fn main() { fn combine_plugins_and_write_to_out_dir() { let out_dir = std::env::var("OUT_DIR").unwrap(); let path = format!("{out_dir}/combined_libs.rs"); - - let mut file = std::fs::File::options() - .truncate(true) - .write(true) - .create(true) - .open(path) - .unwrap(); - + let mut file = std::fs::File::create(path).unwrap(); for plugin in [ include_str!("../nsis-semvercompare/src/lib.rs"), include_str!("../nsis-process/src/lib.rs"), @@ -39,6 +34,6 @@ fn combine_plugins_and_write_to_out_dir() { // skip last line which should be #[cfg(test)] let content = lines[..lines.len() - 1].join("\n"); - std::io::Write::write_all(&mut file, content.as_bytes()).unwrap(); + file.write_all(content.as_bytes()).unwrap(); } } From 97f31178d27961a00941dd8d13a2fbf136ec11b9 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 11:57:02 +0800 Subject: [PATCH 07/27] Vec should be u8 --- crates/nsis-process/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 679ada4..214cb00 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -251,12 +251,13 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { { return false; } - let mut attribute_list = Vec::with_capacity(size); - if InitializeProcThreadAttributeList(attribute_list.as_mut_ptr(), 1, 0, &mut size) == FALSE { + let mut attribute_list: Vec = Vec::with_capacity(size); + if InitializeProcThreadAttributeList(attribute_list.as_mut_ptr() as _, 1, 0, &mut size) == FALSE + { return false; } if UpdateProcThreadAttribute( - attribute_list.as_mut_ptr(), + attribute_list.as_mut_ptr() as _, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as _, &*handle as *const _ as _, @@ -272,7 +273,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { cb: mem::size_of::() as _, ..mem::zeroed() }, - lpAttributeList: attribute_list.as_mut_ptr(), + lpAttributeList: attribute_list.as_mut_ptr() as _, }; let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; let mut command_line = command.to_owned(); From e3f8124d46e14526f5568a1373849dd6b88fe4fc Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 12:04:56 +0800 Subject: [PATCH 08/27] Exctract *handle == 0 to is_invalid --- crates/nsis-process/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 214cb00..d10c1cf 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -234,7 +234,7 @@ fn get_processes(name: &str) -> Vec { /// Ported from https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443 unsafe fn run_as_user(command: &str, arguments: &str) -> bool { let hwnd = OwnedHandle::new(GetShellWindow()); - if *hwnd == 0 { + if hwnd.is_invalid() { return false; } let mut proccess_id = 0; @@ -242,7 +242,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { return false; } let handle = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); - if *handle == 0 { + if handle.is_invalid() { return false; } let mut size = 0; @@ -304,6 +304,10 @@ impl OwnedHandle { fn new(handle: HANDLE) -> Self { Self(handle) } + + fn is_invalid(&self) -> bool { + self.0 == 0 + } } impl Drop for OwnedHandle { From 9f4238a481bf6daa07365c7d96a73ade8b98f595 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 12:17:47 +0800 Subject: [PATCH 09/27] return false on CreateProcessW fail --- crates/nsis-process/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index d10c1cf..91b8f66 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -290,12 +290,14 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { ptr::null(), &startup_info as *const _ as _, &process_info as *const _ as _, - ) != 0 + ) == 0 { + false + } else { CloseHandle(process_info.hProcess); CloseHandle(process_info.hThread); + true } - true } struct OwnedHandle(HANDLE); From 56bbaf58d7fe7b0b7f442267616f269ab381bca5 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 12:22:24 +0800 Subject: [PATCH 10/27] GetWindowThreadProcessId returns 0 on fail --- crates/nsis-process/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 91b8f66..2109eb2 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -238,7 +238,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { return false; } let mut proccess_id = 0; - if GetWindowThreadProcessId(*hwnd, &mut proccess_id) != 0 { + if GetWindowThreadProcessId(*hwnd, &mut proccess_id) == 0 { return false; } let handle = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); From 10399d7778e0a881baf50482f2d85e935d7f13aa Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 12:23:04 +0800 Subject: [PATCH 11/27] Add to demo --- demo.nsi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/demo.nsi b/demo.nsi index b1f9c94..4bfae01 100644 --- a/demo.nsi +++ b/demo.nsi @@ -22,4 +22,7 @@ Section nsis_process::FindProcess "abcdef.exe" Pop $1 DetailPrint "FindProcess(abcdef.exe): $1" -SectionEnd \ No newline at end of file + nsis_process::RunAsUser "C:\\Windows\\System32\\cmd.exe" "/c pause" + Pop $1 + DetailPrint "RunAsUser(cmd, /c pause): $1" +SectionEnd From fe9aa88a3a211c8db6ffce24c80d8c0f1c7b6a93 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 12:24:20 +0800 Subject: [PATCH 12/27] Push arguments to command line on when not empty --- crates/nsis-process/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 2109eb2..8f5ece8 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -277,8 +277,10 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { }; let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; let mut command_line = command.to_owned(); - command_line.push(' '); - command_line.push_str(arguments); + if !arguments.is_empty() { + command_line.push(' '); + command_line.push_str(arguments); + } if CreateProcessW( encode_utf16(command).as_ptr(), encode_utf16(&command_line).as_mut_ptr(), From 07fec45f3cf51d2f0867748a2cfad9b2eabe09ad Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 12:45:25 +0800 Subject: [PATCH 13/27] Use timeout instead of pause --- crates/nsis-process/src/lib.rs | 2 +- demo.nsi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 8f5ece8..defc1f6 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -348,6 +348,6 @@ mod tests { #[test] fn spawn_cmd() { - unsafe { run_as_user("cmd", "/c pause") }; + unsafe { run_as_user("cmd", "/c timeout 3") }; } } diff --git a/demo.nsi b/demo.nsi index 4bfae01..64a6a4b 100644 --- a/demo.nsi +++ b/demo.nsi @@ -22,7 +22,7 @@ Section nsis_process::FindProcess "abcdef.exe" Pop $1 DetailPrint "FindProcess(abcdef.exe): $1" - nsis_process::RunAsUser "C:\\Windows\\System32\\cmd.exe" "/c pause" + nsis_process::RunAsUser "C:\\Windows\\System32\\cmd.exe" "/c timeout 3" Pop $1 - DetailPrint "RunAsUser(cmd, /c pause): $1" + DetailPrint "RunAsUser(cmd, /c timeout 3): $1" SectionEnd From 72d2ac3305c7cd1dc524125a947a855d9d7b9d86 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 15:01:35 +0800 Subject: [PATCH 14/27] Use vec! instead of with_capacity --- crates/nsis-process/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index defc1f6..66f45fe 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -251,7 +251,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { { return false; } - let mut attribute_list: Vec = Vec::with_capacity(size); + let mut attribute_list = vec![0u8; size]; if InitializeProcThreadAttributeList(attribute_list.as_mut_ptr() as _, 1, 0, &mut size) == FALSE { return false; From 3f8b8b5b6c0334398199f48ad67633cb209dbc50 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 15:11:24 +0800 Subject: [PATCH 15/27] Use OwnedHandle --- crates/nsis-process/src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 66f45fe..658debd 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -206,15 +206,15 @@ fn get_processes(name: &str) -> Vec { let mut processes = Vec::new(); unsafe { - let handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + let handle = OwnedHandle::new(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); let mut process = PROCESSENTRY32W { dwSize: mem::size_of::() as u32, ..mem::zeroed() }; - if Process32FirstW(handle, &mut process) != 0 { - while Process32NextW(handle, &mut process) != 0 { + if Process32FirstW(*handle, &mut process) != 0 { + while Process32NextW(*handle, &mut process) != 0 { if current_pid != process.th32ProcessID && decode_utf16_lossy(&process.szExeFile).to_lowercase() == name.to_lowercase() { @@ -222,8 +222,6 @@ fn get_processes(name: &str) -> Vec { } } } - - CloseHandle(handle); } processes From fcfc34958abc56d861be8a25f7c35b96d12e536c Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 15:21:39 +0800 Subject: [PATCH 16/27] Refactor to OwnedHandle --- crates/nsis-process/src/lib.rs | 74 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 658debd..05cd2e0 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -4,6 +4,7 @@ extern crate alloc; use alloc::vec::Vec; use alloc::{borrow::ToOwned, vec}; +use core::ops::DerefMut; use core::{ffi::c_void, mem, ops::Deref, ptr}; use nsis_plugin_api::*; @@ -149,56 +150,49 @@ unsafe fn belongs_to_user(user_sid: *mut c_void, pid: u32) -> bool { fn kill(pid: u32) -> bool { unsafe { - let handle = OpenProcess(PROCESS_TERMINATE, 0, pid); - let success = TerminateProcess(handle, 1); - CloseHandle(handle); + let handle = OwnedHandle::new(OpenProcess(PROCESS_TERMINATE, 0, pid)); + let success = TerminateProcess(*handle, 1); success != 0 } } // Get the SID of a process. Returns None on error. unsafe fn get_sid(pid: u32) -> Option<*mut c_void> { - let handle = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid); + let handle = OwnedHandle::new(OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)); + let mut token_handle = OwnedHandle::new(HANDLE::default()); - let mut sid = None; - let mut token_handle = HANDLE::default(); - - if OpenProcessToken(handle, TOKEN_QUERY, &mut token_handle) != 0 { - let mut info_length = 0; + if OpenProcessToken(*handle, TOKEN_QUERY, &mut *token_handle) == 0 { + return None; + } + let mut info_length = 0; - GetTokenInformation( - token_handle, - TokenUser, - ptr::null_mut(), - 0, - &mut info_length as *mut u32, - ); + GetTokenInformation( + *token_handle, + TokenUser, + ptr::null_mut(), + 0, + &mut info_length as *mut u32, + ); - // GetTokenInformation always returns 0 for the first call so we check if it still gave us the buffer length - if info_length == 0 { - return sid; - } + // GetTokenInformation always returns 0 for the first call so we check if it still gave us the buffer length + if info_length == 0 { + return None; + } - let info = vec![0u8; info_length as usize].as_mut_ptr() as *mut TOKEN_USER; + let info = vec![0u8; info_length as usize].as_mut_ptr() as *mut TOKEN_USER; - if GetTokenInformation( - token_handle, - TokenUser, - info as *mut c_void, - info_length, - &mut info_length, - ) == 0 - { - return sid; - } - - sid = Some((*info).User.Sid) + if GetTokenInformation( + *token_handle, + TokenUser, + info as *mut c_void, + info_length, + &mut info_length, + ) == 0 + { + return None; } - CloseHandle(token_handle); - CloseHandle(handle); - - sid + Some((*info).User.Sid) } fn get_processes(name: &str) -> Vec { @@ -326,6 +320,12 @@ impl Deref for OwnedHandle { } } +impl DerefMut for OwnedHandle { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + #[cfg(test)] mod tests { use super::*; From c17427b2b7e4f670a55bc8a8bc6d9187f014da19 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 15:24:10 +0800 Subject: [PATCH 17/27] Use FALSE --- crates/nsis-process/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 05cd2e0..6118d72 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -152,7 +152,7 @@ fn kill(pid: u32) -> bool { unsafe { let handle = OwnedHandle::new(OpenProcess(PROCESS_TERMINATE, 0, pid)); let success = TerminateProcess(*handle, 1); - success != 0 + success != FALSE } } @@ -161,7 +161,7 @@ unsafe fn get_sid(pid: u32) -> Option<*mut c_void> { let handle = OwnedHandle::new(OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)); let mut token_handle = OwnedHandle::new(HANDLE::default()); - if OpenProcessToken(*handle, TOKEN_QUERY, &mut *token_handle) == 0 { + if OpenProcessToken(*handle, TOKEN_QUERY, &mut *token_handle) == FALSE { return None; } let mut info_length = 0; @@ -187,7 +187,7 @@ unsafe fn get_sid(pid: u32) -> Option<*mut c_void> { info as *mut c_void, info_length, &mut info_length, - ) == 0 + ) == FALSE { return None; } @@ -284,7 +284,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { ptr::null(), &startup_info as *const _ as _, &process_info as *const _ as _, - ) == 0 + ) == FALSE { false } else { From 5c950fa2f92e2a18b304157e15a5123de325c052 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 15:28:53 +0800 Subject: [PATCH 18/27] Change invalid an drop --- crates/nsis-process/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 6118d72..8b28689 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -308,7 +308,9 @@ impl OwnedHandle { impl Drop for OwnedHandle { fn drop(&mut self) { - unsafe { CloseHandle(self.0) }; + if !self.is_invalid() { + unsafe { CloseHandle(self.0) }; + } } } From 3129b278036802870a43c2a038d1df5b5e0433f9 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 15:46:34 +0800 Subject: [PATCH 19/27] Avoid extra cast --- crates/nsis-process/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 8b28689..f88aa58 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -267,7 +267,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { }, lpAttributeList: attribute_list.as_mut_ptr() as _, }; - let process_info = PROCESS_INFORMATION { ..mem::zeroed() }; + let mut process_info = PROCESS_INFORMATION { ..mem::zeroed() }; let mut command_line = command.to_owned(); if !arguments.is_empty() { command_line.push(' '); @@ -283,7 +283,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { ptr::null(), ptr::null(), &startup_info as *const _ as _, - &process_info as *const _ as _, + &mut process_info, ) == FALSE { false From 049650347be7c535ad13efb04ac3ca14aae05595 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 16:05:55 +0800 Subject: [PATCH 20/27] Avoid more extra cast --- crates/nsis-process/src/lib.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index f88aa58..2a35276 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -20,8 +20,9 @@ use windows_sys::Win32::{ CreateProcessW, GetCurrentProcessId, InitializeProcThreadAttributeList, OpenProcess, OpenProcessToken, TerminateProcess, UpdateProcThreadAttribute, CREATE_NEW_PROCESS_GROUP, CREATE_UNICODE_ENVIRONMENT, EXTENDED_STARTUPINFO_PRESENT, - PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, PROCESS_QUERY_INFORMATION, - PROCESS_TERMINATE, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, STARTUPINFOEXW, STARTUPINFOW, + LPPROC_THREAD_ATTRIBUTE_LIST, PROCESS_CREATE_PROCESS, PROCESS_INFORMATION, + PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, + STARTUPINFOEXW, STARTUPINFOW, }, }, UI::WindowsAndMessaging::{GetShellWindow, GetWindowThreadProcessId}, @@ -233,8 +234,8 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { if GetWindowThreadProcessId(*hwnd, &mut proccess_id) == 0 { return false; } - let handle = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); - if handle.is_invalid() { + let process = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); + if process.is_invalid() { return false; } let mut size = 0; @@ -243,16 +244,15 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { { return false; } - let mut attribute_list = vec![0u8; size]; - if InitializeProcThreadAttributeList(attribute_list.as_mut_ptr() as _, 1, 0, &mut size) == FALSE - { + let attribute_list = vec![0u8; size].as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST; + if InitializeProcThreadAttributeList(attribute_list, 1, 0, &mut size) == FALSE { return false; } if UpdateProcThreadAttribute( - attribute_list.as_mut_ptr() as _, + attribute_list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS as _, - &*handle as *const _ as _, + &*process as *const _ as _, mem::size_of::(), ptr::null_mut(), ptr::null(), @@ -265,7 +265,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { cb: mem::size_of::() as _, ..mem::zeroed() }, - lpAttributeList: attribute_list.as_mut_ptr() as _, + lpAttributeList: attribute_list, }; let mut process_info = PROCESS_INFORMATION { ..mem::zeroed() }; let mut command_line = command.to_owned(); From 0a7e9004a28305fcba8d5cbb73799cd5747fe3f9 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 16:11:30 +0800 Subject: [PATCH 21/27] More true false --- crates/nsis-process/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 2a35276..277e8f2 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -2,14 +2,12 @@ extern crate alloc; -use alloc::vec::Vec; -use alloc::{borrow::ToOwned, vec}; -use core::ops::DerefMut; -use core::{ffi::c_void, mem, ops::Deref, ptr}; +use alloc::{borrow::ToOwned, vec, vec::Vec}; +use core::{ffi::c_void, mem, ops::Deref, ops::DerefMut, ptr}; use nsis_plugin_api::*; use windows_sys::Win32::{ - Foundation::{CloseHandle, GetLastError, ERROR_INSUFFICIENT_BUFFER, FALSE, HANDLE}, + Foundation::{CloseHandle, GetLastError, ERROR_INSUFFICIENT_BUFFER, FALSE, HANDLE, TRUE}, Security::{EqualSid, GetTokenInformation, TokenUser, TOKEN_QUERY, TOKEN_USER}, System::{ Diagnostics::ToolHelp::{ @@ -145,7 +143,7 @@ unsafe fn belongs_to_user(user_sid: *mut c_void, pid: u32) -> bool { // Trying to get the sid of a process of another user will give us an "Access Denied" error. // TODO: Consider checking for HRESULT(0x80070005) if we want to return true for other errors to try and kill those processes later. p_sid - .map(|p_sid| EqualSid(user_sid, p_sid) != 0) + .map(|p_sid| EqualSid(user_sid, p_sid) != FALSE) .unwrap_or_default() } @@ -208,8 +206,8 @@ fn get_processes(name: &str) -> Vec { ..mem::zeroed() }; - if Process32FirstW(*handle, &mut process) != 0 { - while Process32NextW(*handle, &mut process) != 0 { + if Process32FirstW(*handle, &mut process) == TRUE { + while Process32NextW(*handle, &mut process) == TRUE { if current_pid != process.th32ProcessID && decode_utf16_lossy(&process.szExeFile).to_lowercase() == name.to_lowercase() { From 19fd72530c68a3cd28e40363ea4d221ce1e5923f Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 5 Jun 2024 16:25:22 +0800 Subject: [PATCH 22/27] Avoid tricky lifetime from direct as_mut_ptr --- crates/nsis-process/src/lib.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 277e8f2..d4e6835 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -158,28 +158,29 @@ fn kill(pid: u32) -> bool { // Get the SID of a process. Returns None on error. unsafe fn get_sid(pid: u32) -> Option<*mut c_void> { let handle = OwnedHandle::new(OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)); + if handle.is_invalid() { + return None; + } let mut token_handle = OwnedHandle::new(HANDLE::default()); - if OpenProcessToken(*handle, TOKEN_QUERY, &mut *token_handle) == FALSE { return None; } - let mut info_length = 0; + let mut info_length = 0; GetTokenInformation( *token_handle, TokenUser, ptr::null_mut(), 0, - &mut info_length as *mut u32, + &mut info_length, ); - // GetTokenInformation always returns 0 for the first call so we check if it still gave us the buffer length if info_length == 0 { return None; } - let info = vec![0u8; info_length as usize].as_mut_ptr() as *mut TOKEN_USER; - + let mut buffer = vec![0u8; info_length as usize]; + let info = buffer.as_mut_ptr() as *mut TOKEN_USER; if GetTokenInformation( *token_handle, TokenUser, @@ -188,10 +189,10 @@ unsafe fn get_sid(pid: u32) -> Option<*mut c_void> { &mut info_length, ) == FALSE { - return None; + None + } else { + Some((*info).User.Sid) } - - Some((*info).User.Sid) } fn get_processes(name: &str) -> Vec { @@ -242,7 +243,8 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { { return false; } - let attribute_list = vec![0u8; size].as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST; + let mut buffer = vec![0u8; size]; + let attribute_list = buffer.as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST; if InitializeProcThreadAttributeList(attribute_list, 1, 0, &mut size) == FALSE { return false; } From 08f20dfce56022dcc0ed8c62861342adf2e6aba1 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Thu, 6 Jun 2024 00:04:41 +0800 Subject: [PATCH 23/27] Apply suggestions from code review Co-authored-by: Amr Bashir --- .changes/run-as-user.md | 3 ++- crates/nsis-process/src/lib.rs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.changes/run-as-user.md b/.changes/run-as-user.md index 939abaa..5193df9 100644 --- a/.changes/run-as-user.md +++ b/.changes/run-as-user.md @@ -1,5 +1,6 @@ --- "nsis_process": "minor" +"nsis_tauri_utils: "minor" --- -Add a new function `RunAsUser` to run command as unelevated user +Add `RunAsUser` to run command as unelevated user diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index d4e6835..d01ec2c 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -150,8 +150,7 @@ unsafe fn belongs_to_user(user_sid: *mut c_void, pid: u32) -> bool { fn kill(pid: u32) -> bool { unsafe { let handle = OwnedHandle::new(OpenProcess(PROCESS_TERMINATE, 0, pid)); - let success = TerminateProcess(*handle, 1); - success != FALSE + TerminateProcess(*handle, 1) == TRUE } } @@ -161,6 +160,7 @@ unsafe fn get_sid(pid: u32) -> Option<*mut c_void> { if handle.is_invalid() { return None; } + let mut token_handle = OwnedHandle::new(HANDLE::default()); if OpenProcessToken(*handle, TOKEN_QUERY, &mut *token_handle) == FALSE { return None; @@ -229,25 +229,30 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { if hwnd.is_invalid() { return false; } + let mut proccess_id = 0; if GetWindowThreadProcessId(*hwnd, &mut proccess_id) == 0 { return false; } + let process = OwnedHandle::new(OpenProcess(PROCESS_CREATE_PROCESS, FALSE, proccess_id)); if process.is_invalid() { return false; } + let mut size = 0; if !(InitializeProcThreadAttributeList(ptr::null_mut(), 1, 0, &mut size) == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { return false; } + let mut buffer = vec![0u8; size]; let attribute_list = buffer.as_mut_ptr() as LPPROC_THREAD_ATTRIBUTE_LIST; if InitializeProcThreadAttributeList(attribute_list, 1, 0, &mut size) == FALSE { return false; } + if UpdateProcThreadAttribute( attribute_list, 0, @@ -260,6 +265,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { { return false; } + let startup_info = STARTUPINFOEXW { StartupInfo: STARTUPINFOW { cb: mem::size_of::() as _, @@ -267,12 +273,13 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { }, lpAttributeList: attribute_list, }; - let mut process_info = PROCESS_INFORMATION { ..mem::zeroed() }; + let mut process_info: PROCESS_INFORMATION = mem::zeroed(); let mut command_line = command.to_owned(); if !arguments.is_empty() { command_line.push(' '); command_line.push_str(arguments); } + if CreateProcessW( encode_utf16(command).as_ptr(), encode_utf16(&command_line).as_mut_ptr(), From 58a259c8cbc9f74b3624fd2d4beaa0fbe17fd08c Mon Sep 17 00:00:00 2001 From: Tony Date: Thu, 6 Jun 2024 00:05:42 +0800 Subject: [PATCH 24/27] Shouldn't use OwnedHandle GetShellWindow --- crates/nsis-process/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index d01ec2c..1b3e308 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -225,13 +225,13 @@ fn get_processes(name: &str) -> Vec { /// /// Ported from https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443 unsafe fn run_as_user(command: &str, arguments: &str) -> bool { - let hwnd = OwnedHandle::new(GetShellWindow()); - if hwnd.is_invalid() { + let hwnd = GetShellWindow(); + if hwnd == 0 { return false; } let mut proccess_id = 0; - if GetWindowThreadProcessId(*hwnd, &mut proccess_id) == 0 { + if GetWindowThreadProcessId(hwnd, &mut proccess_id) == 0 { return false; } From 618407699f512486e044375e15c116296fb17466 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Wed, 5 Jun 2024 21:25:38 +0300 Subject: [PATCH 25/27] Update crates/nsis-process/src/lib.rs --- crates/nsis-process/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 1b3e308..7ca8667 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -231,7 +231,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { } let mut proccess_id = 0; - if GetWindowThreadProcessId(hwnd, &mut proccess_id) == 0 { + if GetWindowThreadProcessId(hwnd, &mut proccess_id) == FALSE { return false; } From 820d702655e8fe9b69f2c22cfe8c8b657095b009 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Wed, 5 Jun 2024 21:26:30 +0300 Subject: [PATCH 26/27] Update .changes/run-as-user.md --- .changes/run-as-user.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changes/run-as-user.md b/.changes/run-as-user.md index 5193df9..55be9ca 100644 --- a/.changes/run-as-user.md +++ b/.changes/run-as-user.md @@ -1,6 +1,6 @@ --- "nsis_process": "minor" -"nsis_tauri_utils: "minor" +"nsis_tauri_utils": "minor" --- Add `RunAsUser` to run command as unelevated user From 8217ea0ba6b9684baf8d853d86a60f77c580bbad Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Wed, 5 Jun 2024 21:28:51 +0300 Subject: [PATCH 27/27] Update crates/nsis-process/src/lib.rs --- crates/nsis-process/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/nsis-process/src/lib.rs b/crates/nsis-process/src/lib.rs index 7ca8667..4a77ba9 100644 --- a/crates/nsis-process/src/lib.rs +++ b/crates/nsis-process/src/lib.rs @@ -231,7 +231,7 @@ unsafe fn run_as_user(command: &str, arguments: &str) -> bool { } let mut proccess_id = 0; - if GetWindowThreadProcessId(hwnd, &mut proccess_id) == FALSE { + if GetWindowThreadProcessId(hwnd, &mut proccess_id) == FALSE as u32 { return false; }