mirror of
https://github.com/a2x/cs2-dumper.git
synced 2025-10-08 12:00:02 +08:00
Release 1.1.4
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
use std::ffi::c_char;
|
||||
use std::mem::offset_of;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
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 {
|
||||
/// Returns the pointer of the interface.
|
||||
pub fn pointer(&self, process: &Process) -> Result<Address> {
|
||||
process
|
||||
.read_memory::<usize>(
|
||||
(self as *const _ as usize + offset_of!(InterfaceReg, create_fn)).into(),
|
||||
)
|
||||
.map(|ptr| ptr.into())
|
||||
}
|
||||
|
||||
/// Returns the name of the interface.
|
||||
/// E.g. "Source2Client002"
|
||||
pub fn name(&self, process: &Process) -> Result<String> {
|
||||
let name_ptr = process.read_memory::<usize>(
|
||||
(self as *const _ as usize + offset_of!(InterfaceReg, name)).into(),
|
||||
)?;
|
||||
|
||||
process.read_string(name_ptr.into())
|
||||
}
|
||||
|
||||
/// Returns the next interface in the list.
|
||||
pub fn next(&self, process: &Process) -> Result<*mut InterfaceReg> {
|
||||
process.read_memory::<*mut InterfaceReg>(
|
||||
(self as *const _ as usize + offset_of!(InterfaceReg, next)).into(),
|
||||
)
|
||||
}
|
||||
}
|
@@ -1,4 +1,3 @@
|
||||
pub use interface::InterfaceReg;
|
||||
pub use schema_class_field_data::SchemaClassFieldData;
|
||||
pub use schema_class_info::SchemaClassInfo;
|
||||
pub use schema_system::SchemaSystem;
|
||||
@@ -7,7 +6,6 @@ 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;
|
||||
|
@@ -1,40 +1,73 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaType;
|
||||
|
||||
/// Represents a class field in a schema.
|
||||
use crate::util::{Address, Process};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
/// Represents data for a field in a schema class.
|
||||
pub struct SchemaClassFieldData<'a> {
|
||||
process: &'a Process,
|
||||
|
||||
/// Address of the class field.
|
||||
addr: Address,
|
||||
address: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaClassFieldData<'a> {
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
/// Creates a new `SchemaClassFieldData` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
/// * `address` - The address of the `SchemaClassFieldData` instance.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `SchemaClassFieldData` - The new `SchemaClassFieldData` instance.
|
||||
pub fn new(process: &'a Process, address: Address) -> Self {
|
||||
Self { process, address }
|
||||
}
|
||||
|
||||
/// Returns the name of the field.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaClassFieldData` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String>` - The name of the field.
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.addr + 0x0)?;
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address)?;
|
||||
|
||||
self.process.read_string_len(name_ptr.into(), 64)
|
||||
self.process.read_string_length(name_ptr.into(), 64)
|
||||
}
|
||||
|
||||
/// Returns the type of the field.
|
||||
/// Returns the `SchemaType` of the field.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaClassFieldData` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<SchemaType>` - The `SchemaType` of the field.
|
||||
pub fn r#type(&self) -> Result<SchemaType> {
|
||||
Ok(SchemaType::new(
|
||||
self.process,
|
||||
self.process.read_memory::<usize>(self.addr + 0x8)?.into(),
|
||||
self.process
|
||||
.read_memory::<usize>(self.address + 0x8)?
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns the offset of the field.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaClassFieldData` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<u16>` - The offset of the field.
|
||||
pub fn offset(&self) -> Result<u16> {
|
||||
self.process.read_memory::<u16>(self.addr + 0x10)
|
||||
self.process.read_memory::<u16>(self.address + 0x10)
|
||||
}
|
||||
}
|
||||
|
@@ -1,47 +1,70 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaClassFieldData;
|
||||
|
||||
/// Represents a class in a schema.
|
||||
use crate::util::{Address, Process};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
/// Represents information about a schema class.
|
||||
pub struct SchemaClassInfo<'a> {
|
||||
process: &'a Process,
|
||||
|
||||
/// Address of the class.
|
||||
addr: Address,
|
||||
|
||||
/// Name of the class.
|
||||
address: Address,
|
||||
class_name: String,
|
||||
}
|
||||
|
||||
impl<'a> SchemaClassInfo<'a> {
|
||||
pub fn new(process: &'a Process, addr: Address, class_name: &str) -> Self {
|
||||
/// Creates a new `SchemaClassInfo` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
/// * `address` - The address of the `SchemaClassInfo` instance.
|
||||
/// * `class_name` - The name of the class.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `SchemaClassInfo` - The new `SchemaClassInfo` instance.
|
||||
pub fn new(process: &'a Process, address: Address, class_name: &str) -> Self {
|
||||
Self {
|
||||
process,
|
||||
addr,
|
||||
address,
|
||||
class_name: class_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name of the class.
|
||||
/// Returns a reference to the name of the class.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaClassInfo` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `&str` - A string slice containing the name of the class.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.class_name
|
||||
}
|
||||
|
||||
/// Returns a list of fields in the class.
|
||||
/// Returns a vector of `SchemaClassFieldData` representing the fields of the schema class.
|
||||
/// If the address of the schema class is null, an empty vector is returned.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaClassInfo` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Vec<SchemaClassFieldData>>` - A vector of `SchemaClassFieldData` representing the fields of the schema class.
|
||||
pub fn fields(&self) -> Result<Vec<SchemaClassFieldData>> {
|
||||
let addr = self.process.read_memory::<usize>(self.addr + 0x28)?;
|
||||
let address = self.process.read_memory::<usize>(self.address + 0x28)?;
|
||||
|
||||
if addr == 0 {
|
||||
if address == 0 {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let count = self.fields_count()?;
|
||||
|
||||
let fields: Vec<SchemaClassFieldData> = (addr..addr + count as usize * 0x20)
|
||||
let fields: Vec<SchemaClassFieldData> = (address..address + count as usize * 0x20)
|
||||
.step_by(0x20)
|
||||
.map(|address| SchemaClassFieldData::new(self.process, address.into()))
|
||||
.collect();
|
||||
@@ -50,21 +73,38 @@ impl<'a> SchemaClassInfo<'a> {
|
||||
}
|
||||
|
||||
/// Returns the number of fields in the class.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaClassInfo` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<u16>` - The number of fields in the class.
|
||||
pub fn fields_count(&self) -> Result<u16> {
|
||||
self.process.read_memory::<u16>(self.addr + 0x1C)
|
||||
self.process.read_memory::<u16>(self.address + 0x1C)
|
||||
}
|
||||
|
||||
/// Returns the parent class.
|
||||
/// Returns the parent `SchemaClassInfo` of the current `SchemaClassInfo` instance.
|
||||
/// If the parent is not found, returns `Ok(None)`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaClassInfo` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Option<SchemaClassInfo>>` - The parent `SchemaClassInfo` of the current `SchemaClassInfo` instance.
|
||||
pub fn parent(&self) -> Result<Option<SchemaClassInfo>> {
|
||||
let addr = self.process.read_memory::<usize>(self.addr + 0x38)?;
|
||||
let address = Address::from(self.process.read_memory::<usize>(self.address + 0x38)?);
|
||||
|
||||
if addr == 0 {
|
||||
if address.is_zero() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let parent = self.process.read_memory::<usize>((addr + 0x8).into())?;
|
||||
let parent = Address::from(self.process.read_memory::<usize>(address + 0x8)?);
|
||||
|
||||
let name_ptr = self.process.read_memory::<usize>((parent + 0x8).into())?;
|
||||
let name_ptr = self.process.read_memory::<usize>(parent + 0x8)?;
|
||||
let name = self.process.read_string(name_ptr.into())?;
|
||||
|
||||
Ok(Some(SchemaClassInfo::new(
|
||||
|
@@ -1,43 +1,57 @@
|
||||
use std::mem;
|
||||
use super::SchemaSystemTypeScope;
|
||||
|
||||
use crate::util::{Address, Process};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaSystemTypeScope;
|
||||
use std::mem;
|
||||
|
||||
/// Represents the schema system.
|
||||
pub struct SchemaSystem<'a> {
|
||||
process: &'a Process,
|
||||
|
||||
/// Address of the schema system.
|
||||
addr: Address,
|
||||
address: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaSystem<'a> {
|
||||
/// Creates a new `SchemaSystem` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<SchemaSystem>` - The new `SchemaSystem` instance.
|
||||
pub fn new(process: &'a Process) -> Result<Self> {
|
||||
let mut addr = process.find_pattern(
|
||||
let mut address = process.find_pattern(
|
||||
"schemasystem.dll",
|
||||
"48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 83 EC 28"
|
||||
)?;
|
||||
).expect("Failed to find SchemaSystem pattern");
|
||||
|
||||
addr = process.resolve_rip(addr, None, None)?;
|
||||
address = process.resolve_rip(address, 0x3, 0x7)?;
|
||||
|
||||
Ok(Self { process, addr })
|
||||
Ok(Self { process, address })
|
||||
}
|
||||
|
||||
/// Returns a list of type scopes.
|
||||
/// Returns a vector of `SchemaSystemTypeScope` objects.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaSystem` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Vec<SchemaSystemTypeScope>>` - A vector of `SchemaSystemTypeScope` objects.
|
||||
pub fn type_scopes(&self) -> Result<Vec<SchemaSystemTypeScope>> {
|
||||
let size = self.process.read_memory::<u32>(self.addr + 0x190)?;
|
||||
let size = self.process.read_memory::<u32>(self.address + 0x190)?;
|
||||
|
||||
if size == 0 {
|
||||
bail!("Type scopes size is 0");
|
||||
}
|
||||
|
||||
let data = self.process.read_memory::<usize>(self.addr + 0x198)?;
|
||||
let data = self.process.read_memory::<usize>(self.address + 0x198)?;
|
||||
|
||||
let mut addresses: Vec<usize> = vec![0; size as usize];
|
||||
let mut addresses = vec![0; size as usize];
|
||||
|
||||
self.process.read_memory_raw(
|
||||
data.into(),
|
||||
@@ -47,7 +61,7 @@ impl<'a> SchemaSystem<'a> {
|
||||
|
||||
let type_scopes: Vec<SchemaSystemTypeScope> = addresses
|
||||
.iter()
|
||||
.map(|&addr| SchemaSystemTypeScope::new(self.process, addr.into()))
|
||||
.map(|&address| SchemaSystemTypeScope::new(self.process, address.into()))
|
||||
.collect();
|
||||
|
||||
Ok(type_scopes)
|
||||
|
@@ -1,49 +1,73 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::{SchemaClassInfo, SchemaTypeDeclaredClass, UtlTsHash};
|
||||
|
||||
/// Represents a schema system type scope.
|
||||
use crate::util::{Address, Process};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
/// Represents a system type scope in the schema.
|
||||
pub struct SchemaSystemTypeScope<'a> {
|
||||
process: &'a Process,
|
||||
|
||||
/// Address of the schema system type scope.
|
||||
addr: Address,
|
||||
address: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaSystemTypeScope<'a> {
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
/// Creates a new `SchemaSystemTypeScope` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
/// * `address` - The address of the `SchemaSystemTypeScope` instance.
|
||||
/// * `class_name` - The name of the class.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `SchemaSystemTypeScope` - The new `SchemaSystemTypeScope` instance.
|
||||
pub fn new(process: &'a Process, address: Address) -> Self {
|
||||
Self { process, address }
|
||||
}
|
||||
|
||||
/// Returns a list of classes in the type scope.
|
||||
/// Returns a vector of `SchemaClassInfo` containing information about all the classes declared in the current scope.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaSystemTypeScope` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Vec<SchemaClassInfo>>` - A vector of `SchemaClassInfo` containing information about all the classes declared in the current scope.
|
||||
pub fn classes(&self) -> Result<Vec<SchemaClassInfo>> {
|
||||
let declared_classes = self
|
||||
.process
|
||||
.read_memory::<UtlTsHash<*mut SchemaTypeDeclaredClass>>(self.addr + 0x588)?;
|
||||
.read_memory::<UtlTsHash<*mut SchemaTypeDeclaredClass>>(self.address + 0x588)?;
|
||||
|
||||
let classes: Vec<SchemaClassInfo> = declared_classes
|
||||
.elements(self.process)?
|
||||
.iter()
|
||||
.filter_map(|&addr| {
|
||||
let addr = Address::from(addr as usize);
|
||||
.filter_map(|&a| {
|
||||
let address = Address::from(a as usize);
|
||||
|
||||
let declared_class = SchemaTypeDeclaredClass::new(self.process, addr);
|
||||
let declared_class = SchemaTypeDeclaredClass::new(self.process, address);
|
||||
|
||||
declared_class
|
||||
.name()
|
||||
.ok()
|
||||
.map(|name| SchemaClassInfo::new(self.process, addr, &name))
|
||||
.map(|name| SchemaClassInfo::new(self.process, address, &name))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(classes)
|
||||
}
|
||||
|
||||
/// Returns the name of the module that the type scope belongs to.
|
||||
/// Returns the name of the module associated with the current `SchemaSystemTypeScope` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaSystemTypeScope` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String>` - The name of the module associated with the current `SchemaSystemTypeScope` instance.
|
||||
pub fn module_name(&self) -> Result<String> {
|
||||
self.process.read_string_len(self.addr + 0x8, 256)
|
||||
self.process.read_string_length(self.address + 0x8, 256)
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use crate::util::{Address, Process};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -6,10 +6,9 @@ use lazy_static::lazy_static;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Map of type names to their C equivalents.
|
||||
/// Map of type names to their `C` equivalents.
|
||||
const TYPE_MAP: &[(&'static str, &'static str)] = &[
|
||||
("uint8", "uint8_t"),
|
||||
("uint16", "uint16_t"),
|
||||
@@ -24,6 +23,8 @@ const TYPE_MAP: &[(&'static str, &'static str)] = &[
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
/// A static HashMap that maps a string to a Regex pattern.
|
||||
/// The Regex pattern is created by wrapping the string with word boundaries `(\b)`.
|
||||
static ref REGEX_MAP: HashMap<&'static str, Regex> = {
|
||||
let mut map = HashMap::with_capacity(TYPE_MAP.len());
|
||||
|
||||
@@ -35,22 +36,38 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
/// Represents a schema type.
|
||||
/// Represents a type in the schema.
|
||||
pub struct SchemaType<'a> {
|
||||
process: &'a Process,
|
||||
|
||||
/// Address of the schema type.
|
||||
addr: Address,
|
||||
address: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaType<'a> {
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
/// Creates a new `SchemaType` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
/// * `address` - The address of the `SchemaType` instance.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `SchemaType` - The new `SchemaType` instance.
|
||||
pub fn new(process: &'a Process, address: Address) -> Self {
|
||||
Self { process, address }
|
||||
}
|
||||
|
||||
/// Returns the name of the type.
|
||||
/// Returns the name of the schema type.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaType` instance.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String>` - The name of the schema type, wrapped in a `Result` object.
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.addr + 0x8)?;
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address + 0x8)?;
|
||||
|
||||
let name = self
|
||||
.process
|
||||
@@ -61,6 +78,15 @@ impl<'a> SchemaType<'a> {
|
||||
Ok(Self::convert_type_name(&name))
|
||||
}
|
||||
|
||||
/// Converts a schema type name to its `C` equivalent.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `type_name` - A string slice that holds the name of the schema type.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `String` - The `C` equivalent of the schema type name.
|
||||
fn convert_type_name(type_name: &str) -> String {
|
||||
let mut result = type_name.to_string();
|
||||
|
||||
|
@@ -1,25 +1,40 @@
|
||||
use crate::util::{Address, Process};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
/// Represents a schema type declared class.
|
||||
/// Represents a declared class type in the schema.
|
||||
pub struct SchemaTypeDeclaredClass<'a> {
|
||||
process: &'a Process,
|
||||
|
||||
/// Address of the schema type declared class.
|
||||
addr: Address,
|
||||
address: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaTypeDeclaredClass<'a> {
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
/// Creates a new `SchemaTypeDeclaredClass` instance.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
/// * `address` - The address of the `SchemaTypeDeclaredClass` instance.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `SchemaTypeDeclaredClass` - The new `SchemaTypeDeclaredClass` instance.
|
||||
pub fn new(process: &'a Process, address: Address) -> Self {
|
||||
Self { process, address }
|
||||
}
|
||||
|
||||
/// Returns the name of the class.
|
||||
/// Returns the name of the declared class.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `SchemaTypeDeclaredClass` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<String>` - The name of the declared class.
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.addr + 0x8)?;
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address + 0x8)?;
|
||||
|
||||
self.process.read_string_len(name_ptr.into(), 64)
|
||||
self.process.read_string_length(name_ptr.into(), 64)
|
||||
}
|
||||
}
|
||||
|
@@ -1,44 +1,63 @@
|
||||
use crate::util::Process;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use std::mem::offset_of;
|
||||
|
||||
use crate::remote::Process;
|
||||
|
||||
/// Represents a hash bucket.
|
||||
/// Represents the internal data of a hash table.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashFixedDataInternal<T, K> {
|
||||
struct HashFixedDataInternal<T, K> {
|
||||
ui_key: K, // 0x0010
|
||||
next: *mut HashFixedDataInternal<T, K>, // 0x0010
|
||||
data: T, // 0x0010
|
||||
}
|
||||
|
||||
/// Implementation of HashFixedDataInternal struct with methods for reading the next element in the hash table.
|
||||
impl<T, K> HashFixedDataInternal<T, K> {
|
||||
pub fn next(&self, process: &Process) -> Result<*mut HashFixedDataInternal<T, K>> {
|
||||
/// Reads the next element in the hash table.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a Result containing a pointer to the next element in the hash table if successful, or an error if unsuccessful.
|
||||
fn next(&self, process: &Process) -> Result<*mut HashFixedDataInternal<T, K>> {
|
||||
process.read_memory::<*mut HashFixedDataInternal<T, K>>(
|
||||
(self as *const _ as usize + offset_of!(HashFixedDataInternal<T, K>, next)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hash bucket.
|
||||
/// Represents the internal data of a hash bucket.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashBucketDataInternal<T, K> {
|
||||
struct HashBucketDataInternal<T, K> {
|
||||
data: T, // 0x0000
|
||||
next: *mut HashFixedDataInternal<T, K>, // 0x0008
|
||||
ui_key: K, // 0x0010
|
||||
}
|
||||
|
||||
impl<T, K> HashBucketDataInternal<T, K> {
|
||||
pub fn next(&self, process: &Process) -> Result<*mut HashFixedDataInternal<T, K>> {
|
||||
/// Reads the next element in the hash table.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a Result containing a pointer to the next element in the hash table if successful, or an error if unsuccessful.
|
||||
fn next(&self, process: &Process) -> Result<*mut HashFixedDataInternal<T, K>> {
|
||||
process.read_memory::<*mut HashFixedDataInternal<T, K>>(
|
||||
(self as *const _ as usize + offset_of!(HashBucketDataInternal<T, K>, next)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hash table.
|
||||
/// Represents allocated data in a hash table.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashAllocatedData<T, K> {
|
||||
@@ -47,17 +66,26 @@ pub struct HashAllocatedData<T, K> {
|
||||
}
|
||||
|
||||
impl<T, K> HashAllocatedData<T, K> {
|
||||
pub fn list(&self, process: &Process) -> Result<[HashFixedDataInternal<T, K>; 128]> {
|
||||
/// Reads the list of elements in the hash table.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns a Result containing a list of elements in the hash table if successful, or an error if unsuccessful.
|
||||
fn list(&self, process: &Process) -> Result<[HashFixedDataInternal<T, K>; 128]> {
|
||||
process.read_memory::<[HashFixedDataInternal<T, K>; 128]>(
|
||||
(self as *const _ as usize + offset_of!(HashAllocatedData<T, K>, list)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hash table.
|
||||
/// A struct representing unallocated data in a hash table.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashUnallocatedData<T, K> {
|
||||
struct HashUnallocatedData<T, K> {
|
||||
next: *mut HashUnallocatedData<T, K>, // 0x0000
|
||||
unknown_1: K, // 0x0008
|
||||
ui_key: K, // 0x0010
|
||||
@@ -66,19 +94,46 @@ pub struct HashUnallocatedData<T, K> {
|
||||
}
|
||||
|
||||
impl<T, K> HashUnallocatedData<T, K> {
|
||||
pub fn next(&self, process: &Process) -> Result<*mut HashUnallocatedData<T, K>> {
|
||||
/// Reads the next `HashUnallocatedData` element in memory.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<*mut HashUnallocatedData<T, K>>` - A Result containing a pointer to the next `HashUnallocatedData` element in memory.
|
||||
fn next(&self, process: &Process) -> Result<*mut HashUnallocatedData<T, K>> {
|
||||
process.read_memory::<*mut HashUnallocatedData<T, K>>(
|
||||
(self as *const _ as usize + offset_of!(HashUnallocatedData<T, K>, next)).into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ui_key(&self, process: &Process) -> Result<K> {
|
||||
/// Reads the UI key of the `HashUnallocatedData` element in memory.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<K>` - A Result containing the UI key of the `HashUnallocatedData` element in memory.
|
||||
fn ui_key(&self, process: &Process) -> Result<K> {
|
||||
process.read_memory::<K>(
|
||||
(self as *const _ as usize + offset_of!(HashUnallocatedData<T, K>, ui_key)).into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn block_list(&self, process: &Process) -> Result<[HashBucketDataInternal<T, K>; 256]> {
|
||||
/// Reads the block list of the `HashUnallocatedData` element in memory.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<[HashBucketDataInternal<T, K>; 256]>` - A Result containing the block list of the `HashUnallocatedData` element in memory.
|
||||
fn block_list(&self, process: &Process) -> Result<[HashBucketDataInternal<T, K>; 256]> {
|
||||
process.read_memory::<[HashBucketDataInternal<T, K>; 256]>(
|
||||
(self as *const _ as usize + offset_of!(HashUnallocatedData<T, K>, block_list)).into(),
|
||||
)
|
||||
@@ -88,15 +143,16 @@ impl<T, K> HashUnallocatedData<T, K> {
|
||||
/// Represents a hash bucket.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashBucket<T, K> {
|
||||
struct HashBucket<T, K> {
|
||||
pad_0: [u8; 0x10], // 0x0000
|
||||
allocated_data: *const HashAllocatedData<T, K>, // 0x0010
|
||||
unallocated_data: *const HashUnallocatedData<T, K>, // 0x0018
|
||||
}
|
||||
|
||||
/// Represents a memory pool used by the `UtlTsHash` class.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct UtlMemoryPool {
|
||||
struct UtlMemoryPool {
|
||||
block_size: i32, // 0x0000
|
||||
blocks_per_blob: i32, // 0x0004
|
||||
grow_mode: i32, // 0x0008
|
||||
@@ -107,14 +163,30 @@ pub struct UtlMemoryPool {
|
||||
|
||||
impl UtlMemoryPool {
|
||||
/// Returns the number of blocks per blob.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `UtlMemoryPool` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `i32` - The number of blocks per blob.
|
||||
#[inline]
|
||||
pub fn block_size(&self) -> i32 {
|
||||
fn block_size(&self) -> i32 {
|
||||
self.blocks_per_blob
|
||||
}
|
||||
|
||||
/// Returns the number of blocks allocated.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `UtlMemoryPool` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `i32` - The number of blocks allocated.
|
||||
#[inline]
|
||||
pub fn count(&self) -> i32 {
|
||||
fn count(&self) -> i32 {
|
||||
self.block_allocated_size
|
||||
}
|
||||
}
|
||||
@@ -132,25 +204,49 @@ where
|
||||
T: Copy,
|
||||
{
|
||||
/// Returns the number of blocks per blob.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `UtlTsHash` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `i32` - The number of blocks per blob.
|
||||
#[inline]
|
||||
pub fn block_size(&self) -> i32 {
|
||||
self.entry_memory.block_size()
|
||||
}
|
||||
|
||||
/// Returns the number of blocks allocated.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `&self` - A reference to the `UtlTsHash` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `i32` - The number of blocks allocated.
|
||||
#[inline]
|
||||
pub fn count(&self) -> i32 {
|
||||
self.entry_memory.count()
|
||||
}
|
||||
|
||||
/// Returns a list of elements in the hash table.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `process` - A reference to the `Process` struct.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<Vec<T>>` - A Result containing a list of elements in the hash table if successful, or an error if unsuccessful.
|
||||
pub fn elements(&self, process: &Process) -> Result<Vec<T>> {
|
||||
let mut address = self.buckets.unallocated_data;
|
||||
|
||||
let min_size = (self.block_size() as usize).min(self.count() as usize);
|
||||
|
||||
let mut list = Vec::with_capacity(min_size);
|
||||
|
||||
let mut address = self.buckets.unallocated_data;
|
||||
|
||||
while !address.is_null() {
|
||||
let block_list = unsafe { (*address).block_list(process) }?;
|
||||
|
||||
|
Reference in New Issue
Block a user