#![allow(dead_code)]
#[link(name="psapi")]
extern "system"
{
fn EnumProcesses(id_processes: *mut u32, cb: u32, cb_needed: *mut u32) -> i32;
fn GetProcessImageFileNameA(handle: usize, image_filename: *mut u8, size: u32) -> u32;
}
#[link(name="kernel32")]
extern "system"
{
fn IsWow64Process(handle: usize, bool_result: *mut i32) -> i32;
fn OpenProcess(desired_access: u32, inherit_handle: i32, process_id: u32) -> usize;
fn GetModuleBaseNameA(handle: usize, module_handle: usize, name: *mut u8, size: u32) -> u32;
fn GetModuleInformation(handle: usize, module_handle: usize, module_pointer: *mut Module, cb: u32) -> i32;
fn EnumProcessModulesEx(handle: usize, modules_array: *mut usize, cb: u32, cb_needed: *mut u32, filter_flag: u32) -> i32;
fn ReadProcessMemory(handle: usize, base_address: *const usize, buffer: *mut u8, size: usize, bytes_read: *mut usize) -> i32;
fn WriteProcessMemory(handle: usize, base_address: *const usize, buffer: *const u8, size: usize, bytes_written: *mut usize) -> i32;
}
const PATH_SIZE: usize = 260;
const PROCESS_ALL_ACCESS: u32 = 0x001F0FFF;
#[repr(C)]
#[derive(Debug)]
#[derive(Clone, Copy)]
#[derive(PartialEq, PartialOrd)]
pub struct Module
{
pub base_address: usize,
pub size_of_image: usize,
pub entry_point: usize
}
#[repr(C)]
#[derive(Debug)]
pub struct Process
{
pub process_name: String,
pub process_handle: usize,
pub process_id: u32,
}
impl Process
{
pub fn new_from_id(process_id: u32) -> Option<Process>
{
let active_process_ids: Vec<u32> = list_processes().unwrap().into_iter().map(|(x, _)| x).collect();
match active_process_ids.iter().position(|&x| x == process_id)
{
None => panic!("Process with \"{}\" id not found", process_id),
Some(_) =>
{
let handle: usize = unsafe {OpenProcess(PROCESS_ALL_ACCESS, 0, process_id)};
let mut image_file_name: [u8; PATH_SIZE] = [0; PATH_SIZE];
unsafe {GetProcessImageFileNameA(handle, &mut image_file_name as *mut u8, 260)};
let file_name_decoded: String = String::from_utf8(image_file_name.to_vec()).unwrap().trim_end_matches("\0").to_string();
match file_name_decoded.split("\\").last()
{
Some(name) => {Some(Process{process_name: name.to_string(), process_handle: handle, process_id: process_id})}
None => {Some(Process{process_name: "".to_string(), process_handle: handle, process_id: process_id})}
}
}
}
}
pub fn new_from_name(process_name: String) -> Option<Process>
{
let active_process_ids: Vec<u32> = list_processes().unwrap().into_iter().map(|(x, _)| x).collect();
let active_process_names: Vec<String> = list_processes().unwrap().into_iter().map(|(_, x)| x).collect();
match active_process_names.into_iter().position(|x| x.to_lowercase() == process_name.to_lowercase())
{
None => panic!("Process with \"{}\" name not found", process_name),
Some(index) =>
{
let handle: usize = unsafe {OpenProcess(PROCESS_ALL_ACCESS, 0, active_process_ids[index])};
let mut image_file_name: [u8; PATH_SIZE] = [0; PATH_SIZE];
unsafe {GetProcessImageFileNameA(handle, &mut image_file_name as *mut u8, 260)};
let file_name_decoded: String = String::from_utf8(image_file_name.to_vec()).unwrap().trim_end_matches("\0").to_string();
match file_name_decoded.split("\\").last()
{
Some(name) => {Some(Process{process_name: name.to_string(), process_handle: handle, process_id: active_process_ids[index]})}
None => {Some(Process{process_name: "".to_string(), process_handle: handle, process_id: active_process_ids[index]})}
}
}
}
}
pub fn is_64x(&self) -> bool
{
let mut is_64: i32 = 0;
if unsafe {IsWow64Process(self.process_handle, &mut is_64 as *mut i32)} != 0 {true} else {false}
}
pub fn read_memory<T>(&self, address: usize) -> Option<T>
{
let mut buffer: T = unsafe {std::mem::zeroed::<T>()};
let mut bytes_read: usize = 0;
let success: i32 = unsafe {ReadProcessMemory(self.process_handle, address as *const usize, &mut buffer as *mut T as *mut u8, std::mem::size_of::<T>(), &mut bytes_read)};
if success != 0 {Some(buffer)} else {None}
}
pub fn write_memory<T>(&self, address: usize, value: T) -> bool
{
let mut bytes_written: usize = 0;
let success: i32 = unsafe {WriteProcessMemory(self.process_handle, address as *const usize, &value as *const T as *const u8, std::mem::size_of::<T>(), &mut bytes_written)};
if success != 0 {true} else {false}
}
pub fn get_module_info(&self, module_name: String) -> Option<Module>
{
let modules = self.list_modules().unwrap();
for (name, module_object) in modules
{
if module_name.to_lowercase() == name.to_lowercase()
{
return Some(module_object);
}
}
None
}
pub fn list_modules(&self) -> Option<Vec<(String, Module)>>
{
let mut current_module_objects: Vec<(String, Module)> = Vec::new();
let mut module_handles: [usize; 2048] = [0; 2048];
let mut cb_needed: u32 = 0;
match unsafe {EnumProcessModulesEx(self.process_handle, &mut module_handles as *mut usize, std::mem::size_of_val(&module_handles) as u32, &mut cb_needed as *mut u32, 0x003)}
{
0 => {}
_ =>
{
let active_modules_count: usize = (cb_needed / std::mem::size_of::<u32>() as u32) as usize;
for module_handle in 0..active_modules_count
{
let mut module_info: Module = unsafe{std::mem::zeroed::<Module>()};
unsafe {GetModuleInformation(self.process_handle, module_handles[module_handle], &mut module_info as *mut Module, std::mem::size_of_val(&mut module_handles) as u32)};
if !current_module_objects.contains(&(get_module_name(self.process_handle, module_handles[module_handle]), module_info))
{
current_module_objects.push((get_module_name(self.process_handle, module_handles[module_handle]), module_info));
}
}
}
}
if !current_module_objects.is_empty() {Some(current_module_objects)} else {None}
}
}
pub fn get_module_name(process_handle: usize, module_hande: usize) -> String
{
let mut buffer: [u8; PATH_SIZE] = [0; PATH_SIZE];
unsafe {GetModuleBaseNameA(process_handle, module_hande, &mut buffer as *mut u8, std::mem::size_of_val(&mut buffer) as u32)};
let decoded_buffer: String = String::from_utf8(buffer.to_vec()).unwrap().trim_end_matches("\0").to_string();
decoded_buffer
}
pub fn list_processes() -> Option<Vec<(u32, String)>>
{
let mut current_process_names: Vec<(u32, String)> = Vec::new();
let mut current_process_ids: [u32; 2048] = [0; 2048];
let mut cb_needed: u32 = 0;
match unsafe {EnumProcesses(current_process_ids.as_mut_ptr(), std::mem::size_of_val(¤t_process_ids) as u32, &mut cb_needed)}
{
0 => {},
_ =>
{
let active_processes_count: usize = (cb_needed / std::mem::size_of::<u32>() as u32) as usize;
for process_id in 0..active_processes_count
{
let handle: usize = unsafe {OpenProcess(PROCESS_ALL_ACCESS, 0, current_process_ids[process_id] as u32)};
match handle
{
0 => {}
_ =>
{
let mut image_file_name: [u8; PATH_SIZE] = [0; PATH_SIZE];
unsafe {GetProcessImageFileNameA(handle, &mut image_file_name as *mut u8, 260)};
let file_name_decoded: String = String::from_utf8(image_file_name.to_vec()).unwrap().trim_end_matches("\0").to_string();
match file_name_decoded.split("\\").last()
{
None => {}
Some(name) => {current_process_names.push((current_process_ids[process_id], name.to_string()))}
}
}
}
}
}
}
if !current_process_names.is_empty() {Some(current_process_names)} else {None}
}