Add python file builder

This commit is contained in:
a2x
2023-10-17 12:06:23 +10:00
parent c55bdf15a2
commit 0a86db6b40
86 changed files with 17670 additions and 436 deletions

View File

@@ -7,14 +7,14 @@ use super::FileBuilder;
#[derive(Debug, PartialEq)]
pub struct JsonFileBuilder {
json: Value,
namespace: String,
current_namespace: String,
}
impl Default for JsonFileBuilder {
fn default() -> Self {
Self {
json: Value::Object(Map::new()),
namespace: String::new(),
current_namespace: String::new(),
}
}
}
@@ -29,7 +29,7 @@ impl FileBuilder for JsonFileBuilder {
}
fn write_namespace(&mut self, _output: &mut dyn Write, name: &str) -> Result<()> {
self.namespace = name.to_string();
self.current_namespace = name.to_string();
Ok(())
}
@@ -42,7 +42,9 @@ impl FileBuilder for JsonFileBuilder {
_comment: Option<&str>,
) -> Result<()> {
if let Some(map) = self.json.as_object_mut() {
let entry = map.entry(&self.namespace).or_insert_with(|| json!({}));
let entry = map
.entry(&self.current_namespace)
.or_insert_with(|| json!({}));
if let Some(object) = entry.as_object_mut() {
object.insert(name.to_string(), json!(value));

View File

@@ -4,12 +4,14 @@ pub use cpp_file_builder::CppFileBuilder;
pub use csharp_file_builder::CSharpFileBuilder;
pub use file_builder::FileBuilder;
pub use json_file_builder::JsonFileBuilder;
pub use python_file_builder::PythonFileBuilder;
pub use rust_file_builder::RustFileBuilder;
pub mod cpp_file_builder;
pub mod csharp_file_builder;
pub mod file_builder;
pub mod json_file_builder;
pub mod python_file_builder;
pub mod rust_file_builder;
#[derive(Debug, PartialEq)]
@@ -17,6 +19,7 @@ pub enum FileBuilderEnum {
CppFileBuilder(CppFileBuilder),
CSharpFileBuilder(CSharpFileBuilder),
JsonFileBuilder(JsonFileBuilder),
PythonFileBuilder(PythonFileBuilder),
RustFileBuilder(RustFileBuilder),
}
@@ -54,6 +57,7 @@ impl FileBuilderEnum {
FileBuilderEnum::CppFileBuilder(builder) => builder,
FileBuilderEnum::CSharpFileBuilder(builder) => builder,
FileBuilderEnum::JsonFileBuilder(builder) => builder,
FileBuilderEnum::PythonFileBuilder(builder) => builder,
FileBuilderEnum::RustFileBuilder(builder) => builder,
}
}

View File

@@ -0,0 +1,43 @@
use std::io::{Result, Write};
use super::FileBuilder;
#[derive(Debug, PartialEq)]
pub struct PythonFileBuilder;
impl FileBuilder for PythonFileBuilder {
fn extension(&mut self) -> &str {
"py"
}
fn write_top_level(&mut self, _output: &mut dyn Write) -> Result<()> {
Ok(())
}
fn write_namespace(&mut self, output: &mut dyn Write, name: &str) -> Result<()> {
write!(output, "class {}:\n", name)?;
Ok(())
}
fn write_variable(
&mut self,
output: &mut dyn Write,
name: &str,
value: usize,
comment: Option<&str>,
) -> Result<()> {
match comment {
Some(comment) => write!(output, " {} = {:#X} # {}\n", name, value, comment),
None => write!(output, " {} = {:#X}\n", name, value),
}
}
fn write_closure(&mut self, output: &mut dyn Write, eof: bool) -> Result<()> {
if !eof {
write!(output, "\n")?;
}
Ok(())
}
}

View File

@@ -1,51 +1,21 @@
use std::ffi::c_char;
use std::mem::offset_of;
use convert_case::{Case, Casing};
use crate::builder::FileBuilderEnum;
use crate::dumpers::Entry;
use crate::error::Result;
use crate::remote::Process;
use crate::sdk::InterfaceReg;
use super::{generate_files, Entries};
#[derive(Debug)]
#[repr(C)]
struct InterfaceReg {
create_fn: *const (), // 0x0000
name: *const c_char, // 0x0008
next: *mut InterfaceReg, // 0x0010
}
impl InterfaceReg {
pub fn ptr(&self, process: &Process) -> Result<usize> {
process
.read_memory::<usize>(self as *const _ as usize + offset_of!(InterfaceReg, create_fn))
}
pub fn name(&self, process: &Process) -> Result<String> {
let name_ptr = process
.read_memory::<usize>(self as *const _ as usize + offset_of!(InterfaceReg, name))?;
process.read_string(name_ptr)
}
pub fn next(&self, process: &Process) -> Result<*mut InterfaceReg> {
process.read_memory::<*mut InterfaceReg>(
self as *const _ as usize + offset_of!(InterfaceReg, next),
)
}
}
pub fn dump_interfaces(builders: &mut Vec<FileBuilderEnum>, process: &Process) -> Result<()> {
let module_names = process.get_loaded_modules()?;
let mut entries = Entries::new();
for module_name in module_names {
if module_name == "crashhandler64.dll" {
continue;
}
for module_name in process
.get_loaded_modules()?
.into_iter()
.filter(|module_name| *module_name != "crashhandler64.dll")
{
let module = process.get_module_by_name(&module_name)?;
if let Some(create_interface_export) = module.export("CreateInterface") {
@@ -70,7 +40,12 @@ pub fn dump_interfaces(builders: &mut Vec<FileBuilderEnum>, process: &Process) -
);
entries
.entry(module_name.replace(".", "_"))
.entry(
module_name
.replace(".", "_")
.to_case(Case::Snake)
.to_case(Case::Pascal),
)
.or_default()
.push(Entry {
name: name.clone(),

View File

@@ -2,6 +2,8 @@ use std::collections::BTreeMap;
use std::fs::File;
use std::io::Write;
use chrono::Utc;
use crate::builder::{FileBuilder, FileBuilderEnum};
use crate::error::Result;
@@ -34,29 +36,23 @@ pub fn generate_file(
let mut file = File::create(file_path)?;
builder.write_top_level(&mut file)?;
write_banner_to_file(&mut file, builder.extension())?;
if builder.extension() != "json" {
write!(
file,
"/*\n * https://github.com/a2x/cs2-dumper\n * {}\n */\n\n",
chrono::Utc::now()
)?;
}
builder.write_top_level(&mut file)?;
let len = entries.len();
for (i, pair) in entries.iter().enumerate() {
builder.write_namespace(&mut file, pair.0)?;
for entry in pair.1 {
pair.1.iter().try_for_each(|entry| {
builder.write_variable(
&mut file,
&entry.name,
entry.value,
entry.comment.as_deref(),
)?;
}
)
})?;
builder.write_closure(&mut file, i == len - 1)?;
}
@@ -65,12 +61,28 @@ pub fn generate_file(
}
pub fn generate_files(
builders: &mut Vec<FileBuilderEnum>,
builders: &mut [FileBuilderEnum],
entries: &Entries,
file_name: &str,
) -> Result<()> {
for builder in builders {
generate_file(builder, &entries, file_name)?;
builders
.iter_mut()
.try_for_each(|builder| generate_file(builder, entries, file_name))
}
fn write_banner_to_file(file: &mut File, extension: &str) -> Result<()> {
let chrono_now = Utc::now();
const URL: &str = "https://github.com/a2x/cs2-dumper";
let banner = match extension {
"json" => None,
"py" => Some(format!("'''\n{}\n{}\n'''\n\n", URL, chrono_now)),
_ => Some(format!("/*\n * {}\n * {}\n */\n\n", URL, chrono_now)),
};
if let Some(banner) = banner {
write!(file, "{}", banner)?;
}
Ok(())

View File

@@ -1,5 +1,7 @@
use std::fs::File;
use convert_case::{Case, Casing};
use crate::builder::FileBuilderEnum;
use crate::config::{Config, Operation::*};
use crate::dumpers::Entry;
@@ -84,72 +86,81 @@ pub fn dump_offsets(builders: &mut Vec<FileBuilderEnum>, process: &Process) -> R
for signature in config.signatures {
let module = process.get_module_by_name(&signature.module)?;
if let Ok(address) = process.find_pattern(&signature.module, &signature.pattern) {
let mut address = Address::from(address);
let mut address = match process.find_pattern(&signature.module, &signature.pattern) {
Ok(a) => Address::from(a),
Err(_) => {
log::error!("Failed to find pattern for {}.", signature.name);
for operation in signature.operations {
match operation {
Add { value } => address += value,
Dereference { times, size } => {
let times = times.unwrap_or(1);
let size = size.unwrap_or(8);
for _ in 0..times {
process.read_memory_raw(
address.0,
&mut address.0 as *mut _ as *mut _,
size,
)?;
}
}
Jmp { offset, length } => {
address = process.resolve_jmp(address.0, offset, length)?.into()
}
RipRelative { offset, length } => {
address = process.resolve_rip(address.0, offset, length)?.into()
}
Slice { start, end } => {
let mut result: usize = 0;
process.read_memory_raw(
address.add(start).0,
&mut result as *mut _ as *mut _,
end - start,
)?;
address = result.into();
}
Subtract { value } => address -= value,
}
continue;
}
};
let (name, value) = if address.0 < module.base() {
log::debug!(" └─ {} @ {:#X}", signature.name, address.0);
for operation in signature.operations {
match operation {
Add { value } => address += value,
Dereference { times, size } => {
let times = times.unwrap_or(1);
let size = size.unwrap_or(8);
(signature.name, address.0)
} else {
log::debug!(
" └─ {} @ {:#X} ({} + {:#X})",
signature.name,
address,
signature.module,
address.sub(module.base())
);
for _ in 0..times {
process.read_memory_raw(
address.0,
&mut address.0 as *mut _ as *mut _,
size,
)?;
}
}
Jmp { offset, length } => {
address = process.resolve_jmp(address.0, offset, length)?.into()
}
RipRelative { offset, length } => {
address = process.resolve_rip(address.0, offset, length)?.into()
}
Slice { start, end } => {
let mut result: usize = 0;
(signature.name, address.sub(module.base()).0)
};
process.read_memory_raw(
address.add(start).0,
&mut result as *mut _ as *mut _,
end - start,
)?;
entries
.entry(signature.module.replace(".", "_"))
.or_default()
.push(Entry {
name,
value,
comment: None,
});
} else {
log::error!("Failed to find pattern for {}.", signature.name);
address = result.into();
}
Subtract { value } => address -= value,
}
}
let (name, value) = if address.0 < module.base() {
log::debug!(" └─ {} @ {:#X}", signature.name, address.0);
(signature.name, address.0)
} else {
log::debug!(
" └─ {} @ {:#X} ({} + {:#X})",
signature.name,
address,
signature.module,
address.sub(module.base())
);
(signature.name, address.sub(module.base()).0)
};
entries
.entry(
signature
.module
.replace(".", "_")
.to_case(Case::Snake)
.to_case(Case::Pascal),
)
.or_default()
.push(Entry {
name,
value,
comment: None,
});
}
generate_files(builders, &entries, "offsets")?;

View File

@@ -9,7 +9,7 @@ use windows::core::Error as WindowsError;
#[derive(Debug, Error)]
pub enum Error {
#[error("Buffer size mismatch: expected {0}, got {1}")]
#[error("Buffer size mismatch. Expected {0}, got {1}")]
BufferSizeMismatch(usize, usize),
#[error("Invalid magic: {0:#X}")]
@@ -18,14 +18,14 @@ pub enum Error {
#[error("IO error: {0}")]
IOError(#[from] io::Error),
#[error("Module not found")]
ModuleNotFound,
#[error("Module not found: {0}")]
ModuleNotFound(String),
#[error("Pattern not found")]
PatternNotFound,
#[error("Pattern not found: {0}")]
PatternNotFound(String),
#[error("Process not found")]
ProcessNotFound,
#[error("Process not found: {0}")]
ProcessNotFound(String),
#[error("Serde error: {0}")]
SerdeError(#[from] SerdeError),

View File

@@ -67,6 +67,7 @@ fn main() -> Result<()> {
FileBuilderEnum::CppFileBuilder(CppFileBuilder),
FileBuilderEnum::CSharpFileBuilder(CSharpFileBuilder),
FileBuilderEnum::JsonFileBuilder(JsonFileBuilder::default()),
FileBuilderEnum::PythonFileBuilder(PythonFileBuilder),
FileBuilderEnum::RustFileBuilder(RustFileBuilder),
];

View File

@@ -58,7 +58,7 @@ impl Process {
}
}
Err(Error::PatternNotFound)
Err(Error::PatternNotFound(pattern.to_owned()))
}
pub fn get_loaded_modules(&self) -> Result<Vec<String>> {
@@ -108,7 +108,7 @@ impl Process {
}
}
Err(Error::ModuleNotFound)
Err(Error::ModuleNotFound(module_name.to_owned()))
}
pub fn read_memory_raw(&self, address: usize, buffer: *mut c_void, size: usize) -> Result<()> {
@@ -215,7 +215,7 @@ impl Process {
}
}
Err(Error::ProcessNotFound)
Err(Error::ProcessNotFound(process_name.to_owned()))
}
fn pattern_to_bytes(pattern: &str) -> Vec<i32> {

33
src/sdk/interface.rs Normal file
View File

@@ -0,0 +1,33 @@
use std::ffi::c_char;
use std::mem::offset_of;
use crate::error::Result;
use crate::remote::Process;
#[derive(Debug)]
#[repr(C)]
pub struct InterfaceReg {
pub create_fn: *const (), // 0x0000
pub name: *const c_char, // 0x0008
pub next: *mut InterfaceReg, // 0x0010
}
impl InterfaceReg {
pub fn ptr(&self, process: &Process) -> Result<usize> {
process
.read_memory::<usize>(self as *const _ as usize + offset_of!(InterfaceReg, create_fn))
}
pub fn name(&self, process: &Process) -> Result<String> {
let name_ptr = process
.read_memory::<usize>(self as *const _ as usize + offset_of!(InterfaceReg, name))?;
process.read_string(name_ptr)
}
pub fn next(&self, process: &Process) -> Result<*mut InterfaceReg> {
process.read_memory::<*mut InterfaceReg>(
self as *const _ as usize + offset_of!(InterfaceReg, next),
)
}
}

View File

@@ -1,3 +1,4 @@
pub use interface::InterfaceReg;
pub use schema_class_field_data::SchemaClassFieldData;
pub use schema_class_info::SchemaClassInfo;
pub use schema_system::SchemaSystem;
@@ -6,6 +7,7 @@ pub use schema_type::SchemaType;
pub use schema_type_declared_class::SchemaTypeDeclaredClass;
pub use utl_ts_hash::UtlTsHash;
pub mod interface;
pub mod schema_class_field_data;
pub mod schema_class_info;
pub mod schema_system;