diff --git a/Cargo.toml b/Cargo.toml index 992980c..6f11a02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "cs2-dumper" version = "1.1.0" authors = ["a2x"] edition = "2021" +readme = "README.md" repository = "https://github.com/a2x/cs2-dumper" license = "MIT" diff --git a/README.md b/README.md index 4ac25c1..57080b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# CS2 Dumper +# cs2-dumper -Tool to automatically dump offsets and interfaces for Counter-Strike: 2. +External offsets/interfaces dumper for Counter-Strike: 2, written in Rust. # Generated Files @@ -8,6 +8,10 @@ Generated files are stored in the `generated` directory. 📂 [Pre-generated Files](./generated) +# Running Tests + +`cargo test -- --nocapture` + # License Please refer to the [LICENSE](./LICENSE) file for more details. diff --git a/config.json b/config.json index 299e1a3..f7bc66f 100644 --- a/config.json +++ b/config.json @@ -25,34 +25,36 @@ { "name": "dwForceAttack", "module": "client.dll", - "pattern": "48 8B 15 ? ? ? ? 48 8D 0D ? ? ? ? E9 7D 69 FD 00", + "pattern": "48 8D 0D ? ? ? ? E9 D4 4B B4 FF", "operations": [ { "type": "ripRelative" }, { - "type": "dereference" + "type": "subtract", + "value": 8 }, { "type": "add", - "value": 440 + "value": 48 } ] }, { "name": "dwForceAttack2", "module": "client.dll", - "pattern": "48 8B 15 ? ? ? ? 48 8D 0D ? ? ? ? E9 7D 69 FD 00", + "pattern": "48 8D 0D ? ? ? ? E9 E4 4B B4 FF", "operations": [ { "type": "ripRelative" }, { - "type": "dereference" + "type": "subtract", + "value": 8 }, { "type": "add", - "value": 584 + "value": 48 } ] }, diff --git a/src/dumpers/interfaces.rs b/src/dumpers/interfaces.rs index 6efd0f4..aeac459 100644 --- a/src/dumpers/interfaces.rs +++ b/src/dumpers/interfaces.rs @@ -36,7 +36,7 @@ pub fn dump_interfaces(builders: &mut Vec, process: &Process) - interface_version, interface_ptr, module_name, - interface_ptr - module.address() + interface_ptr - module.base() ); entries @@ -44,7 +44,7 @@ pub fn dump_interfaces(builders: &mut Vec, process: &Process) - .or_default() .push(Entry { name: interface_version.clone(), - value: interface_ptr - module.address(), + value: interface_ptr - module.base(), comment: None, }); diff --git a/src/dumpers/offsets.rs b/src/dumpers/offsets.rs index aad099e..d432cc7 100644 --- a/src/dumpers/offsets.rs +++ b/src/dumpers/offsets.rs @@ -9,6 +9,69 @@ use crate::remote::Process; use super::{generate_files, Entries}; +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn build_number() -> Result<()> { + let process = Process::new("cs2.exe")?; + + let engine_base = process.get_module_by_name("engine2.dll")?.base(); + + let build_number = process.read_memory::(engine_base + 0x487514)?; + + println!("Build number: {}", build_number); + + Ok(()) + } + + #[test] + fn global_vars() -> Result<()> { + let process = Process::new("cs2.exe")?; + + let client_base = process.get_module_by_name("client.dll")?.base(); + + let global_vars = process.read_memory::(client_base + 0x1692EE8)?; + + let current_map_name = + process.read_string(process.read_memory::(global_vars + 0x188)?)?; + + println!("Current map name: {}", current_map_name); + + Ok(()) + } + + #[test] + fn local_player() -> Result<()> { + let process = Process::new("cs2.exe")?; + + let client_base = process.get_module_by_name("client.dll")?.base(); + + let local_player_controller = process.read_memory::(client_base + 0x17DE508)?; + + let player_name = process.read_string(local_player_controller + 0x610)?; + + println!("Name: {}", player_name); + + Ok(()) + } + + #[test] + fn window_size() -> Result<()> { + let process = Process::new("cs2.exe")?; + + let engine_base = process.get_module_by_name("engine2.dll")?.base(); + + let window_width = process.read_memory::(engine_base + 0x538670)?; + let window_height = process.read_memory::(engine_base + 0x538674)?; + + println!("Window size: {}x{}", window_width, window_height); + + Ok(()) + } +} + pub fn dump_offsets(builders: &mut Vec, process: &Process) -> Result<()> { let file = File::open("config.json")?; @@ -60,7 +123,7 @@ pub fn dump_offsets(builders: &mut Vec, process: &Process) -> R } } - let (name, value) = if address.0 < module.address() { + let (name, value) = if address.0 < module.base() { log::debug!(" └─ {} @ {:#X}", signature.name, address.0); (signature.name, address.0) @@ -70,10 +133,10 @@ pub fn dump_offsets(builders: &mut Vec, process: &Process) -> R signature.name, address, signature.module, - address.sub(module.address()) + address.sub(module.base()) ); - (signature.name, address.sub(module.address()).0) + (signature.name, address.sub(module.base()).0) }; entries diff --git a/src/remote/module.rs b/src/remote/module.rs index d8407c4..eb1f7ff 100644 --- a/src/remote/module.rs +++ b/src/remote/module.rs @@ -24,7 +24,7 @@ pub struct Section { } pub struct Module<'a> { - address: usize, + base: usize, nt_headers: &'a IMAGE_NT_HEADERS64, size: u32, exports: Vec, @@ -32,10 +32,10 @@ pub struct Module<'a> { } impl<'a> Module<'a> { - pub fn new(process: &'a Process, address: usize) -> Result { + pub fn new(process: &'a Process, base: usize) -> Result { let mut headers: [u8; 0x1000] = [0; 0x1000]; - process.read_memory_raw(address, headers.as_mut_ptr() as *mut _, headers.len())?; + process.read_memory_raw(base, headers.as_mut_ptr() as *mut _, headers.len())?; if headers.len() < mem::size_of::() { return Err(Error::BufferSizeMismatch( @@ -60,11 +60,11 @@ impl<'a> Module<'a> { let size = nt_headers.OptionalHeader.SizeOfImage; - let exports = unsafe { Self::parse_exports(process, address, size, nt_headers)? }; - let sections = unsafe { Self::parse_sections(address, nt_headers) }; + let exports = unsafe { Self::parse_exports(process, base, size, nt_headers)? }; + let sections = unsafe { Self::parse_sections(base, nt_headers) }; Ok(Self { - address, + base, nt_headers, size, exports, @@ -73,8 +73,8 @@ impl<'a> Module<'a> { } #[inline] - pub fn address(&self) -> usize { - self.address + pub fn base(&self) -> usize { + self.base } #[inline] diff --git a/src/remote/process.rs b/src/remote/process.rs index c088b41..d7df783 100644 --- a/src/remote/process.rs +++ b/src/remote/process.rs @@ -35,7 +35,7 @@ impl Process { let mut module_data: Vec = vec![0; module.size() as usize]; self.read_memory_raw( - module.address(), + module.base(), module_data.as_mut_ptr() as *mut _, module_data.len(), )?; @@ -54,7 +54,7 @@ impl Process { } if found { - return Ok(module.address() + i); + return Ok(module.base() + i); } }