Skip to content

Commit 81fc8c0

Browse files
authored
Add a bunch of documentation and examples. Play around with 'cargo doc' (#3)
1 parent 753cc2f commit 81fc8c0

12 files changed

+655
-147
lines changed

Cargo.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

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

29-
30-
[dependencies]
31-
3229
[dependencies.windows]
3330
version = "0.56.0"
3431
features = [

examples/dsr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ fn main()
7979
println!("{:?}", w32_str);
8080
println!("{:?}", vec_u16_to_u8(&w32_str));
8181

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

src/helpers.rs

+22-11
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,22 @@
1717
use std::path::Path;
1818
use windows::core::{PCSTR, PCWSTR};
1919

20-
pub fn scan(code: &[u8], pattern: &[Option<u8>]) -> Option<usize>
20+
/// Naive linear search for a needle in a haystack with wildcards
21+
pub fn scan(haystack: &[u8], needle: &[Option<u8>]) -> Option<usize>
2122
{
22-
if code.len() == 0
23+
if haystack.len() == 0
2324
{
2425
return None;
2526
}
2627

27-
for i in 0..code.len() - pattern.len()
28+
for i in 0..haystack.len() - needle.len()
2829
{
2930
let mut found = true;
30-
for j in 0..pattern.len()
31+
for j in 0..needle.len()
3132
{
32-
if let Some(byte) = pattern[j]
33+
if let Some(byte) = needle[j]
3334
{
34-
if byte != code[i + j]
35+
if byte != haystack[i + j]
3536
{
3637
found = false;
3738
break;
@@ -46,6 +47,9 @@ pub fn scan(code: &[u8], pattern: &[Option<u8>]) -> Option<usize>
4647
return None;
4748
}
4849

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

70+
/// Retrieve only the filename portion from a filepath.
71+
pub fn get_file_name_from_string(str: &String) -> String
72+
{
73+
return String::from(Path::new(&str).file_name().unwrap().to_str().unwrap());
74+
}
75+
76+
/// Win32 memes. Use with caution.
6677
pub fn vec_u16_to_u8(vec_u16: &Vec<u16>) -> Vec<u8>
6778
{
6879
return unsafe { vec_u16.align_to::<u8>().1.to_vec() };
6980
}
7081

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

76-
pub fn get_file_name_from_string(str: &String) -> String
77-
{
78-
return String::from(Path::new(&str).file_name().unwrap().to_str().unwrap());
79-
}
80-
88+
/// Win32 memes. Use with caution.
8189
pub fn get_w32str_from_str(str: &str) -> Vec<u16>
8290
{
8391
return str.encode_utf16().collect();
8492
}
93+
94+
/// Win32 memes. Use with caution.
8595
pub fn get_pcwstr_from_str(str: &str) -> PCWSTR
8696
{
8797
let vec: Vec<u16> = str.encode_utf16().collect();
8898
return PCWSTR(vec.as_ptr());
8999
}
90100

101+
/// Win32 memes. Use with caution.
91102
pub fn get_pcstr_from_str(str: &str) -> PCSTR
92103
{
93104
return PCSTR(str.as_ptr());

src/pointer.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,28 @@ use std::rc::Rc;
1919
use crate::read_write::{BaseReadWrite, ReadWrite};
2020
use crate::process_data::ProcessData;
2121

22+
23+
/// Represents a pointer path that is dynamically resolved each read/write operation.
24+
/// This ensures that the pointer is always valid. Race conditions can occur and the pointer could encounter
25+
/// a null pointer along the path. Should always be constructed via the Process struct.
26+
///
27+
/// # Example
28+
///
29+
/// ```
30+
/// use mem_rs::prelude::*;
31+
///
32+
/// let mut process = Process::new("name_of_process.exe");
33+
/// process.refresh()?;
34+
/// let pointer = process.create_pointer(0x1234, vec![0]);
35+
/// let data = pointer.read_u8_rel(Some(0x1234));
36+
/// ```
2237
pub struct Pointer
2338
{
2439
process_data: Rc<RefCell<ProcessData>>,
2540
is_64_bit: bool,
2641
base_address: usize,
2742
offsets: Vec<usize>,
43+
/// Set this to true to print each memory address while resolving the pointer path.
2844
pub debug: bool,
2945
}
3046

@@ -45,7 +61,7 @@ impl Default for Pointer
4561

4662
impl Pointer
4763
{
48-
pub fn new(process_data: Rc<RefCell<ProcessData>>, is_64_bit: bool, base_address: usize, offsets: Vec<usize>) -> Self
64+
pub(crate) fn new(process_data: Rc<RefCell<ProcessData>>, is_64_bit: bool, base_address: usize, offsets: Vec<usize>) -> Self
4965
{
5066
Pointer
5167
{
@@ -57,6 +73,7 @@ impl Pointer
5773
}
5874
}
5975

76+
/// Get the base address of this pointer, without resolving offsets.
6077
pub fn get_base_address(&self) -> usize
6178
{
6279
return self.base_address;

src/process/inject_dll.rs

+27
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs).
2+
// Copyright (c) 2022 Frank van der Stam.
3+
// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, version 3.
8+
//
9+
// This program is distributed in the hope that it will be useful, but
10+
// WITHOUT ANY WARRANTY without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
// General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
117
use std::ffi::c_void;
218
use std::mem::size_of;
319
use windows::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress};
@@ -9,6 +25,17 @@ use crate::prelude::*;
925

1026
impl Process
1127
{
28+
/// Attempts to inject a dll into the attached process using LoadLibraryW
29+
///
30+
/// # Examples
31+
///
32+
/// ```
33+
/// use mem_rs::prelude::*;
34+
///
35+
/// let mut process = Process::new("name_of_process.exe");
36+
/// process.refresh().expect("Failed to attach/refresh!");
37+
/// process.inject_dll(r#"C:\temp\native.dll"#).expect("Failed to inject!");
38+
/// ```
1239
pub fn inject_dll(&self, dll_path: &str) -> Result<(), String>
1340
{
1441
let mut path_w32_str: Vec<u16> = dll_path.encode_utf16().collect();

src/process/mod.rs

+41-2
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,37 @@ mod process_name;
3030

3131
const STILL_ACTIVE: u32 = 259;
3232

33-
33+
/// Wraps a native process and allows memory access/manipulation
34+
///
35+
/// # Examples
36+
///
37+
/// ```
38+
/// use mem_rs::prelude::*;
39+
///
40+
/// let mut process = Process::new("name_of_process.exe");
41+
/// if process.refresh().is_ok()
42+
/// {
43+
/// process.write_memory_abs(0x1234, &u32::to_ne_bytes(10));
44+
/// let result = process.read_u32_rel(Some(0x1234));
45+
/// println!("Result: {}", result);
46+
/// }
47+
/// ```
3448
pub struct Process
3549
{
3650
process_data: Rc<RefCell<ProcessData>>
3751
}
3852

3953
impl Process
4054
{
41-
///Create a new process where name is the name of the executable
55+
/// Creates a new process based on the process name.
56+
///
57+
/// # Examples
58+
///
59+
/// ```
60+
/// use mem_rs::prelude::*;
61+
///
62+
/// let mut process = Process::new("name_of_process.exe");
63+
/// ```
4264
pub fn new(name: &str) -> Self
4365
{
4466
Process
@@ -57,6 +79,23 @@ impl Process
5779
}
5880
}
5981

82+
/// Returns if the process is "attached" and can be read/written from/to
83+
///
84+
/// # Examples
85+
///
86+
/// ```
87+
/// use mem_rs::prelude::*;
88+
///
89+
/// let mut process = Process::new("name_of_process.exe");
90+
/// //returns false
91+
/// let not_attached = process.is_attached();
92+
///
93+
/// //refreshing the process will cause it to become attached
94+
/// process.refresh().unwrap();
95+
///
96+
/// //if name_of_process.exe is running, will return true
97+
/// let attached = process.is_attached();
98+
/// ```
6099
pub fn is_attached(&self) -> bool {return self.process_data.borrow().attached;}
61100
}
62101

src/process/process_modules.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
// This file is part of the mem-rs distribution (https://github.com/FrankvdStam/mem-rs).
2+
// Copyright (c) 2022 Frank van der Stam.
3+
// https://github.com/FrankvdStam/mem-rs/blob/main/LICENSE
4+
//
5+
// This program is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, version 3.
8+
//
9+
// This program is distributed in the hope that it will be useful, but
10+
// WITHOUT ANY WARRANTY without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
// General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
117
use std::ffi::c_void;
218
use std::mem::size_of;
319
use windows::Win32::Foundation::{HANDLE, HINSTANCE, HMODULE, MAX_PATH};

0 commit comments

Comments
 (0)