#[allow(non_snake_case)]
mod context;
mod wintrust_sys;
use super::Error;
use wintrust_sys::*;
pub(crate) struct Verifier(Vec<u16>);
pub(crate) use context::Context;
impl Verifier {
pub fn for_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self, Error> {
use std::os::windows::ffi::OsStrExt;
let mut path_vec: Vec<u16> = path.as_ref().as_os_str().encode_wide().collect();
path_vec.push(0);
Ok(Self(path_vec))
}
pub fn for_pid(pid: i32) -> Result<Self, Error> {
let path = get_process_path(pid as _).map_err(|e| Error::IoError(e))?;
Self::for_file(path)
}
pub fn verify(&self) -> Result<Context, Error> {
let mut file_info = WINTRUST_FILE_INFO {
cbStruct: std::mem::size_of::<WINTRUST_FILE_INFO>() as _,
pcwszFilePath: self.0.as_ptr(),
hFile: std::ptr::null_mut(),
pgKnownSubject: std::ptr::null(),
};
let mut data = WINTRUST_DATA {
cbStruct: std::mem::size_of::<WINTRUST_DATA>() as _,
pPolicyCallbackData: std::ptr::null_mut(),
pSIPClientData: std::ptr::null_mut(),
dwUIChoice: WTD_UI_NONE,
fdwRevocationChecks: WTD_REVOKE_NONE,
dwUnionChoice: WTD_CHOICE_FILE,
u: Default::default(),
dwStateAction: WTD_STATEACTION_VERIFY,
hWVTStateData: std::ptr::null_mut(),
pwszURLReference: std::ptr::null_mut(),
dwProvFlags: WTD_DISABLE_MD2_MD4
| WTD_REVOCATION_CHECK_END_CERT
| WTD_NO_IE4_CHAIN_FLAG,
dwUIContext: WTD_UICONTEXT_EXECUTE,
pSignatureSettings: std::ptr::null_mut(),
};
*unsafe { data.u.pFile_mut() } = &mut file_info;
let mut guid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
match unsafe {
WinVerifyTrust(
INVALID_HANDLE_VALUE as _,
&mut guid,
&mut data as *mut _ as _,
)
} {
0 => {}
_ => {
let _ = Context::new(data.hWVTStateData); let err = std::io::Error::last_os_error();
if err.raw_os_error() == Some(winapi::shared::winerror::TRUST_E_NOSIGNATURE) {
return Err(Error::Unsigned);
} else {
return Err(Error::IoError(err));
}
}
}
Context::new(data.hWVTStateData)
}
}
fn get_process_path(proc_id: u32) -> std::io::Result<String> {
use winapi::shared::minwindef;
use winapi::um::{processthreadsapi, winbase, winnt};
let mut buf = [0u16; 2048];
unsafe {
let proc_handle = match processthreadsapi::OpenProcess(
winnt::PROCESS_QUERY_LIMITED_INFORMATION,
minwindef::FALSE,
proc_id,
) {
handle if handle.is_null() => return Err(std::io::Error::last_os_error()),
handle => handle,
};
let mut path_len = buf.len() as _;
match winbase::QueryFullProcessImageNameW(proc_handle, 0, buf.as_mut_ptr(), &mut path_len) {
0 => Err(std::io::Error::last_os_error()),
_ => Ok(String::from_utf16_lossy(&buf[..path_len as usize])),
}
}
}