Skip to content

Commit

Permalink
Add a bunch of documentation and examples. Play around with 'cargo doc'
Browse files Browse the repository at this point in the history
  • Loading branch information
FrankvdStam committed May 23, 2024
1 parent 753cc2f commit ade93e9
Show file tree
Hide file tree
Showing 12 changed files with 655 additions and 147 deletions.
5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

[package]
name = "mem-rs"
version = "0.1.5"
version = "0.1.6"
edition = "2021"
readme = "README.md"
homepage = "https://github.com/FrankvdStam/mem-rs"
Expand All @@ -26,9 +26,6 @@ keywords = ["memory", "gamedev"]
categories = ["memory-management", "games", "development-tools"]
description = "pattern scanning and abstraction for pointers in memory of running processes"


[dependencies]

[dependencies.windows]
version = "0.56.0"
features = [
Expand Down
4 changes: 2 additions & 2 deletions examples/dsr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ fn main()
println!("{:?}", w32_str);
println!("{:?}", vec_u16_to_u8(&w32_str));

let alloated_str = String::from(str);
let collected: Vec<u16> = alloated_str.encode_utf16().collect();
let allocated_str = String::from(str);
let collected: Vec<u16> = allocated_str.encode_utf16().collect();
println!("{:?}", collected);
unsafe { println!("{:?}", collected.align_to::<u8>()); }

Expand Down
33 changes: 22 additions & 11 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,22 @@
use std::path::Path;
use windows::core::{PCSTR, PCWSTR};

pub fn scan(code: &[u8], pattern: &[Option<u8>]) -> Option<usize>
/// Naive linear search for a needle in a haystack with wildcards
pub fn scan(haystack: &[u8], needle: &[Option<u8>]) -> Option<usize>
{
if code.len() == 0
if haystack.len() == 0
{
return None;
}

for i in 0..code.len() - pattern.len()
for i in 0..haystack.len() - needle.len()
{
let mut found = true;
for j in 0..pattern.len()
for j in 0..needle.len()
{
if let Some(byte) = pattern[j]
if let Some(byte) = needle[j]
{
if byte != code[i + j]
if byte != haystack[i + j]
{
found = false;
break;
Expand All @@ -46,6 +47,9 @@ pub fn scan(code: &[u8], pattern: &[Option<u8>]) -> Option<usize>
return None;
}

/// Converts a string of hex characters into a byte pattern with wildcards.
/// ? is the character used for wildcards.
/// Hex characters don't have to be prefixed with 0x
pub fn to_pattern(str: &str) -> Vec<Option<u8>>
{
let mut vec = Vec::new();
Expand All @@ -63,31 +67,38 @@ pub fn to_pattern(str: &str) -> Vec<Option<u8>>
return vec;
}

/// Retrieve only the filename portion from a filepath.
pub fn get_file_name_from_string(str: &String) -> String
{
return String::from(Path::new(&str).file_name().unwrap().to_str().unwrap());
}

/// Win32 memes. Use with caution.
pub fn vec_u16_to_u8(vec_u16: &Vec<u16>) -> Vec<u8>
{
return unsafe { vec_u16.align_to::<u8>().1.to_vec() };
}

/// Win32 memes. Use with caution.
pub fn w32str_to_string(w32str: &Vec<u16>) -> String
{
return w32str.iter().map(|&v| (v & 0xFF) as u8).take_while(|&c| c != 0).map(|c| c as char).collect();
}

pub fn get_file_name_from_string(str: &String) -> String
{
return String::from(Path::new(&str).file_name().unwrap().to_str().unwrap());
}

/// Win32 memes. Use with caution.
pub fn get_w32str_from_str(str: &str) -> Vec<u16>
{
return str.encode_utf16().collect();
}

/// Win32 memes. Use with caution.
pub fn get_pcwstr_from_str(str: &str) -> PCWSTR
{
let vec: Vec<u16> = str.encode_utf16().collect();
return PCWSTR(vec.as_ptr());
}

/// Win32 memes. Use with caution.
pub fn get_pcstr_from_str(str: &str) -> PCSTR
{
return PCSTR(str.as_ptr());
Expand Down
19 changes: 18 additions & 1 deletion src/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,28 @@ use std::rc::Rc;
use crate::read_write::{BaseReadWrite, ReadWrite};
use crate::process_data::ProcessData;


/// Represents a pointer path that is dynamically resolved each read/write operation.
/// This ensures that the pointer is always valid. Race conditions can occur and the pointer could encounter
/// a null pointer along the path. Should always be constructed via the Process struct.
///
/// # Example
///
/// ```
/// use mem_rs::prelude::*;
///
/// let mut process = Process::new("name_of_process.exe");
/// process.refresh()?;
/// let pointer = process.create_pointer(0x1234, vec![0]);
/// let data = pointer.read_u8_rel(Some(0x1234));
/// ```
pub struct Pointer
{
process_data: Rc<RefCell<ProcessData>>,
is_64_bit: bool,
base_address: usize,
offsets: Vec<usize>,
/// Set this to true to print each memory address while resolving the pointer path.
pub debug: bool,
}

Expand All @@ -45,7 +61,7 @@ impl Default for Pointer

impl Pointer
{
pub fn new(process_data: Rc<RefCell<ProcessData>>, is_64_bit: bool, base_address: usize, offsets: Vec<usize>) -> Self
pub(crate) fn new(process_data: Rc<RefCell<ProcessData>>, is_64_bit: bool, base_address: usize, offsets: Vec<usize>) -> Self
{
Pointer
{
Expand All @@ -57,6 +73,7 @@ impl Pointer
}
}

/// Get the base address of this pointer, without resolving offsets.
pub fn get_base_address(&self) -> usize
{
return self.base_address;
Expand Down
27 changes: 27 additions & 0 deletions src/process/inject_dll.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs).
// Copyright (c) 2022 Frank van der Stam.
// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use std::ffi::c_void;
use std::mem::size_of;
use windows::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress};
Expand All @@ -9,6 +25,17 @@ use crate::prelude::*;

impl Process
{
/// Attempts to inject a dll into the attached process using LoadLibraryW
///
/// # Examples
///
/// ```
/// use mem_rs::prelude::*;
///
/// let mut process = Process::new("name_of_process.exe");
/// process.refresh().expect("Failed to attach/refresh!");
/// process.inject_dll(r#"C:\temp\native.dll"#).expect("Failed to inject!");
/// ```
pub fn inject_dll(&self, dll_path: &str) -> Result<(), String>
{
let mut path_w32_str: Vec<u16> = dll_path.encode_utf16().collect();
Expand Down
43 changes: 41 additions & 2 deletions src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,37 @@ mod process_name;

const STILL_ACTIVE: u32 = 259;


/// Wraps a native process and allows memory access/manipulation
///
/// # Examples
///
/// ```
/// use mem_rs::prelude::*;
///
/// let mut process = Process::new("name_of_process.exe");
/// if process.refresh().is_ok()
/// {
/// process.write_memory_abs(0x1234, &u32::to_ne_bytes(10));
/// let result = process.read_u32_rel(Some(0x1234));
/// println!("Result: {}", result);
/// }
/// ```
pub struct Process
{
process_data: Rc<RefCell<ProcessData>>
}

impl Process
{
///Create a new process where name is the name of the executable
/// Creates a new process based on the process name.
///
/// # Examples
///
/// ```
/// use mem_rs::prelude::*;
///
/// let mut process = Process::new("name_of_process.exe");
/// ```
pub fn new(name: &str) -> Self
{
Process
Expand All @@ -57,6 +79,23 @@ impl Process
}
}

/// Returns if the process is "attached" and can be read/written from/to
///
/// # Examples
///
/// ```
/// use mem_rs::prelude::*;
///
/// let mut process = Process::new("name_of_process.exe");
/// //returns false
/// let not_attached = process.is_attached();
///
/// //refreshing the process will cause it to become attached
/// process.refresh().unwrap();
///
/// //if name_of_process.exe is running, will return true
/// let attached = process.is_attached();
/// ```
pub fn is_attached(&self) -> bool {return self.process_data.borrow().attached;}
}

16 changes: 16 additions & 0 deletions src/process/process_modules.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs).
// Copyright (c) 2022 Frank van der Stam.
// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use std::ffi::c_void;
use std::mem::size_of;
use windows::Win32::Foundation::{HANDLE, HINSTANCE, HMODULE, MAX_PATH};
Expand Down
Loading

0 comments on commit ade93e9

Please sign in to comment.