Last active
March 1, 2022 14:01
-
-
Save MolotovCherry/e3ce2adfa79055777fabb81de2e03376 to your computer and use it in GitHub Desktop.
Rust WinAPI (windows-rs) process Privilege granter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[dependencies] | |
thiserror = "1.0.30" | |
[dependencies.windows] | |
version = "0.33.0" | |
features = [ | |
"Win32_System_Threading", | |
"Win32_Foundation", | |
"Win32_Security", | |
"Win32_System_SystemServices" | |
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::ffi::CString; | |
use windows::Win32::System::SystemServices::SE_DEBUG_NAME; | |
use windows::Win32::System::Threading::{TerminateProcess, OpenProcess, PROCESS_TERMINATE, PROCESS_QUERY_INFORMATION, OpenProcessToken}; | |
use windows::Win32::Foundation::{GetLastError, CloseHandle, HANDLE, LUID}; | |
use windows::Win32::Security::{TOKEN_ADJUST_PRIVILEGES, LookupPrivilegeValueA, TOKEN_PRIVILEGES, SE_PRIVILEGE_ENABLED, AdjustTokenPrivileges, TOKEN_PRIVILEGES_ATTRIBUTES}; | |
use windows::core::PCSTR; | |
use thiserror::Error; | |
#[derive(Error, Debug)] | |
pub enum ProcessError { | |
#[error("Process termination failed -> {process} : {pid}) -> code: {errcode}")] | |
TerminationFailed { | |
process: String, | |
pid: u32, | |
errcode: u32 | |
}, | |
#[error("HANDLE is NULL -> {process} : {pid}) -> code: {errcode}")] | |
NullHandle { | |
process: String, | |
pid: u32, | |
errcode: u32 | |
}, | |
#[error("Failed to close HANDLE -> {process} : {pid}) -> code: {errcode}")] | |
CloseHandleFailed { | |
process: String, | |
pid: u32, | |
errcode: u32 | |
}, | |
#[error("Failed to open process token")] | |
OpenProcessTokenFailed { | |
errcode: u32 | |
}, | |
#[error("Failed to lookup privilege")] | |
PrivilegeLookupFailed { | |
name: String, | |
errcode: u32 | |
}, | |
#[error("Adjust token privilege failed")] | |
AdjustTokenPrivilegeFailed { | |
name: String, | |
errcode: u32 | |
} | |
} | |
fn set_privilege(name: &str, state: bool) -> Result<(), Box<dyn Error>> { | |
unsafe { | |
let handle = OpenProcess(PROCESS_QUERY_INFORMATION, false, std::process::id()); | |
if handle.is_invalid() { | |
return Err(Box::new(ProcessError::NullHandle { | |
process: env!("CARGO_PKG_NAME").to_string(), | |
pid: std::process::id(), | |
errcode: GetLastError().0 | |
})); | |
} | |
let mut token_handle = HANDLE(0); | |
let res: bool = OpenProcessToken( | |
handle, | |
TOKEN_ADJUST_PRIVILEGES, | |
&mut token_handle as *mut _ | |
).into(); | |
if !res { | |
return Err(Box::new(ProcessError::OpenProcessTokenFailed { | |
errcode: GetLastError().0 | |
})); | |
} | |
let mut luid = LUID::default(); | |
let privilege = CString::new(name)?; | |
let res: bool = LookupPrivilegeValueA( | |
PCSTR::default(), | |
PCSTR(privilege.as_ptr() as *const _), | |
&mut luid as *mut _ | |
).into(); | |
if !res { | |
return Err(Box::new(ProcessError::PrivilegeLookupFailed { | |
name: name.to_string(), | |
errcode: GetLastError().0 | |
})); | |
} | |
let mut tp = TOKEN_PRIVILEGES::default(); | |
tp.PrivilegeCount = 1; | |
tp.Privileges[0].Luid = luid; | |
if state { | |
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; | |
} else { | |
tp.Privileges[0].Attributes = TOKEN_PRIVILEGES_ATTRIBUTES(0u32); | |
} | |
let res: bool = AdjustTokenPrivileges( | |
token_handle, | |
false, | |
&tp as *const _, | |
std::mem::size_of::<TOKEN_PRIVILEGES>() as u32, | |
std::ptr::null_mut() as *mut _, | |
std::ptr::null_mut() as *mut _ | |
).into(); | |
if !res { | |
return Err(Box::new(ProcessError::AdjustTokenPrivilegeFailed { | |
name: name.to_string(), | |
errcode: GetLastError().0 | |
})); | |
} | |
let res: bool = CloseHandle(handle).into(); | |
if !res { | |
return Err(Box::new(ProcessError::CloseHandleFailed { | |
process: env!("CARGO_PKG_NAME").to_string(), | |
pid: std::process::id(), | |
errcode: GetLastError().0 | |
})); | |
} | |
let res: bool = CloseHandle(token_handle).into(); | |
if !res { | |
return Err(Box::new(ProcessError::CloseHandleFailed { | |
process: env!("CARGO_PKG_NAME").to_string(), | |
pid: std::process::id(), | |
errcode: GetLastError().0 | |
})); | |
} | |
} | |
Ok(()) | |
} | |
fn kill_process(name: &str, pid: u32) -> Result<(), ProcessError> { | |
unsafe { | |
let handle = OpenProcess(PROCESS_TERMINATE, false, pid); | |
if handle.is_invalid() { | |
return Err(ProcessError::NullHandle { | |
process: name.to_string(), | |
pid, | |
errcode: GetLastError().0 | |
}); | |
} | |
let res: bool = TerminateProcess(handle, 0).into(); | |
if !res { | |
return Err(ProcessError::TerminationFailed { | |
process: name.to_string(), | |
pid, | |
errcode: GetLastError().0 | |
}); | |
} | |
let res: bool = CloseHandle(handle).into(); | |
if !res { | |
return Err(ProcessError::CloseHandleFailed { | |
process: name.to_string(), | |
pid, | |
errcode: GetLastError().0 | |
}); | |
} | |
} | |
Ok(()) | |
} | |
fn main() -> Result<(), Box<dyn Error> { | |
// Program MUST be run as admin for this to work | |
// Amongst other things, this will allow the program to terminate SYSTEM processes | |
// For list of privileges, please see: | |
// https://docs.microsoft.com/en-us/windows/win32/secauthz/privilege-constants | |
set_privilege(SE_DEBUG_NAME, true)?; | |
// get the process PID you want to kill somewhere | |
kill_process("foobar.exe", 1234)?; | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment