mirror of
https://github.com/a2x/cs2-dumper.git
synced 2025-10-08 12:00:02 +08:00
📦 Game Update 13963 (2)
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
use std::ffi::c_char;
|
||||
use std::mem::offset_of;
|
||||
|
||||
use crate::error::Result;
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -13,21 +15,29 @@ pub struct InterfaceReg {
|
||||
}
|
||||
|
||||
impl InterfaceReg {
|
||||
pub fn ptr(&self, process: &Process) -> Result<usize> {
|
||||
/// 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))
|
||||
.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))?;
|
||||
let name_ptr = process.read_memory::<usize>(
|
||||
(self as *const _ as usize + offset_of!(InterfaceReg, name)).into(),
|
||||
)?;
|
||||
|
||||
process.read_string(name_ptr)
|
||||
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),
|
||||
(self as *const _ as usize + offset_of!(InterfaceReg, next)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -1,31 +1,40 @@
|
||||
use crate::error::Result;
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaType;
|
||||
|
||||
/// Represents a class field in a schema.
|
||||
pub struct SchemaClassFieldData<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
|
||||
/// Address of the class field.
|
||||
addr: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaClassFieldData<'a> {
|
||||
pub fn new(process: &'a Process, address: usize) -> Self {
|
||||
Self { process, address }
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
}
|
||||
|
||||
/// Returns the name of the field.
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address)?;
|
||||
let name_ptr = self.process.read_memory::<usize>(self.addr + 0x0)?;
|
||||
|
||||
self.process.read_string(name_ptr)
|
||||
self.process.read_string_len(name_ptr.into(), 64)
|
||||
}
|
||||
|
||||
/// Returns the type of the field.
|
||||
pub fn r#type(&self) -> Result<SchemaType> {
|
||||
let type_ptr = self.process.read_memory::<usize>(self.address + 0x8)?;
|
||||
|
||||
Ok(SchemaType::new(self.process, type_ptr))
|
||||
Ok(SchemaType::new(
|
||||
self.process,
|
||||
self.process.read_memory::<usize>(self.addr + 0x8)?.into(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns the offset of the field.
|
||||
pub fn offset(&self) -> Result<u16> {
|
||||
self.process.read_memory::<u16>(self.address + 0x10)
|
||||
self.process.read_memory::<u16>(self.addr + 0x10)
|
||||
}
|
||||
}
|
||||
|
@@ -1,59 +1,76 @@
|
||||
use crate::error::Result;
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaClassFieldData;
|
||||
|
||||
/// Represents a class in a schema.
|
||||
pub struct SchemaClassInfo<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
|
||||
/// Address of the class.
|
||||
addr: Address,
|
||||
|
||||
/// Name of the class.
|
||||
class_name: String,
|
||||
}
|
||||
|
||||
impl<'a> SchemaClassInfo<'a> {
|
||||
pub fn new(process: &'a Process, address: usize, class_name: &str) -> Self {
|
||||
pub fn new(process: &'a Process, addr: Address, class_name: &str) -> Self {
|
||||
Self {
|
||||
process,
|
||||
address,
|
||||
addr,
|
||||
class_name: class_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name of the class.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.class_name
|
||||
}
|
||||
|
||||
/// Returns a list of fields in the class.
|
||||
pub fn fields(&self) -> Result<Vec<SchemaClassFieldData>> {
|
||||
let addr = self.process.read_memory::<usize>(self.addr + 0x28)?;
|
||||
|
||||
if addr == 0 {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let count = self.fields_count()?;
|
||||
|
||||
let base_address = self.process.read_memory::<usize>(self.address + 0x28)?;
|
||||
|
||||
let fields: Vec<SchemaClassFieldData> = (0..count as usize)
|
||||
.map(|i| base_address + (i * 0x20))
|
||||
.filter_map(|address| {
|
||||
if address != 0 {
|
||||
Some(SchemaClassFieldData::new(self.process, address))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
let fields: Vec<SchemaClassFieldData> = (addr..addr + count as usize * 0x20)
|
||||
.step_by(0x20)
|
||||
.map(|address| SchemaClassFieldData::new(self.process, address.into()))
|
||||
.collect();
|
||||
|
||||
Ok(fields)
|
||||
}
|
||||
|
||||
/// Returns the number of fields in the class.
|
||||
pub fn fields_count(&self) -> Result<u16> {
|
||||
self.process.read_memory::<u16>(self.address + 0x1C)
|
||||
self.process.read_memory::<u16>(self.addr + 0x1C)
|
||||
}
|
||||
|
||||
/// Returns the parent class.
|
||||
pub fn parent(&self) -> Result<Option<SchemaClassInfo>> {
|
||||
let addr = self.process.read_memory::<u64>(self.address + 0x38)?;
|
||||
let addr = self.process.read_memory::<usize>(self.addr + 0x38)?;
|
||||
|
||||
if addr == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let parent = self.process.read_memory::<u64>(addr as usize + 0x8)?;
|
||||
let name = self.process.read_string(self.process.read_memory::<usize>(parent as usize + 0x8)?)?;
|
||||
Ok(Some(SchemaClassInfo::new(self.process, parent as usize, &name)))
|
||||
let parent = self.process.read_memory::<usize>((addr + 0x8).into())?;
|
||||
|
||||
let name_ptr = self.process.read_memory::<usize>((parent + 0x8).into())?;
|
||||
let name = self.process.read_string(name_ptr.into())?;
|
||||
|
||||
Ok(Some(SchemaClassInfo::new(
|
||||
self.process,
|
||||
parent.into(),
|
||||
&name,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
@@ -1,42 +1,53 @@
|
||||
use std::mem;
|
||||
|
||||
use crate::error::Result;
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaSystemTypeScope;
|
||||
|
||||
/// Represents the schema system.
|
||||
pub struct SchemaSystem<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
|
||||
/// Address of the schema system.
|
||||
addr: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaSystem<'a> {
|
||||
pub fn new(process: &'a Process) -> Result<Self> {
|
||||
let mut address = process.find_pattern(
|
||||
let mut addr = 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"
|
||||
)?;
|
||||
|
||||
address = process.resolve_rip(address, None, None)?;
|
||||
addr = process.resolve_rip(addr, None, None)?;
|
||||
|
||||
Ok(Self { process, address })
|
||||
Ok(Self { process, addr })
|
||||
}
|
||||
|
||||
/// Returns a list of type scopes.
|
||||
pub fn type_scopes(&self) -> Result<Vec<SchemaSystemTypeScope>> {
|
||||
let size = self.process.read_memory::<u32>(self.address + 0x190)?;
|
||||
let data = self.process.read_memory::<usize>(self.address + 0x198)?;
|
||||
let size = self.process.read_memory::<u32>(self.addr + 0x190)?;
|
||||
|
||||
if size == 0 {
|
||||
bail!("Type scopes size is 0");
|
||||
}
|
||||
|
||||
let data = self.process.read_memory::<usize>(self.addr + 0x198)?;
|
||||
|
||||
let mut addresses: Vec<usize> = vec![0; size as usize];
|
||||
|
||||
self.process.read_memory_raw(
|
||||
data,
|
||||
data.into(),
|
||||
addresses.as_mut_ptr() as *mut _,
|
||||
addresses.len() * mem::size_of::<usize>(),
|
||||
)?;
|
||||
|
||||
let type_scopes: Vec<SchemaSystemTypeScope> = addresses
|
||||
.iter()
|
||||
.map(|&address| SchemaSystemTypeScope::new(self.process, address))
|
||||
.map(|&addr| SchemaSystemTypeScope::new(self.process, addr.into()))
|
||||
.collect();
|
||||
|
||||
Ok(type_scopes)
|
||||
|
@@ -1,42 +1,49 @@
|
||||
use crate::error::Result;
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::{SchemaClassInfo, SchemaTypeDeclaredClass, UtlTsHash};
|
||||
|
||||
/// Represents a schema system type scope.
|
||||
pub struct SchemaSystemTypeScope<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
|
||||
/// Address of the schema system type scope.
|
||||
addr: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaSystemTypeScope<'a> {
|
||||
pub fn new(process: &'a Process, address: usize) -> Self {
|
||||
Self { process, address }
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
}
|
||||
|
||||
/// Returns a list of classes in the type scope.
|
||||
pub fn classes(&self) -> Result<Vec<SchemaClassInfo>> {
|
||||
let classes = self
|
||||
let declared_classes = self
|
||||
.process
|
||||
.read_memory::<UtlTsHash<*mut SchemaTypeDeclaredClass>>(self.address + 0x588)?;
|
||||
.read_memory::<UtlTsHash<*mut SchemaTypeDeclaredClass>>(self.addr + 0x588)?;
|
||||
|
||||
let classes: Vec<SchemaClassInfo> = classes
|
||||
let classes: Vec<SchemaClassInfo> = declared_classes
|
||||
.elements(self.process)?
|
||||
.iter()
|
||||
.filter_map(|&address| {
|
||||
let address = address as usize;
|
||||
.filter_map(|&addr| {
|
||||
let addr = Address::from(addr as usize);
|
||||
|
||||
let declared_class = SchemaTypeDeclaredClass::new(self.process, address);
|
||||
let declared_class = SchemaTypeDeclaredClass::new(self.process, addr);
|
||||
|
||||
declared_class
|
||||
.name()
|
||||
.ok()
|
||||
.map(|name| SchemaClassInfo::new(self.process, address, &name))
|
||||
.map(|name| SchemaClassInfo::new(self.process, addr, &name))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(classes)
|
||||
}
|
||||
|
||||
/// Returns the name of the module that the type scope belongs to.
|
||||
pub fn module_name(&self) -> Result<String> {
|
||||
self.process.read_string(self.address + 0x8)
|
||||
self.process.read_string_len(self.addr + 0x8, 256)
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,15 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
/// Map of type names to their C equivalents.
|
||||
const TYPE_MAP: &[(&'static str, &'static str)] = &[
|
||||
("uint8", "uint8_t"),
|
||||
("uint16", "uint16_t"),
|
||||
@@ -32,22 +35,26 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
/// Represents a schema type.
|
||||
pub struct SchemaType<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
|
||||
/// Address of the schema type.
|
||||
addr: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaType<'a> {
|
||||
pub fn new(process: &'a Process, address: usize) -> Self {
|
||||
Self { process, address }
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
}
|
||||
|
||||
/// Returns the name of the type.
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address + 0x8)?;
|
||||
let name_ptr = self.process.read_memory::<usize>(self.addr + 0x8)?;
|
||||
|
||||
let name = self
|
||||
.process
|
||||
.read_string(name_ptr)?
|
||||
.read_string(name_ptr.into())?
|
||||
.replace(" ", "")
|
||||
.to_string();
|
||||
|
||||
|
@@ -1,19 +1,25 @@
|
||||
use crate::error::Result;
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::mem::Address;
|
||||
use crate::remote::Process;
|
||||
|
||||
/// Represents a schema type declared class.
|
||||
pub struct SchemaTypeDeclaredClass<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
|
||||
/// Address of the schema type declared class.
|
||||
addr: Address,
|
||||
}
|
||||
|
||||
impl<'a> SchemaTypeDeclaredClass<'a> {
|
||||
pub fn new(process: &'a Process, address: usize) -> Self {
|
||||
Self { process, address }
|
||||
pub fn new(process: &'a Process, addr: Address) -> Self {
|
||||
Self { process, addr }
|
||||
}
|
||||
|
||||
/// Returns the name of the class.
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address + 0x8)?;
|
||||
let name_ptr = self.process.read_memory::<usize>(self.addr + 0x8)?;
|
||||
|
||||
self.process.read_string(name_ptr)
|
||||
self.process.read_string_len(name_ptr.into(), 64)
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,10 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use std::mem::offset_of;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::remote::Process;
|
||||
|
||||
/// Represents a hash bucket.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashFixedDataInternal<T, K> {
|
||||
@@ -14,11 +16,12 @@ pub struct HashFixedDataInternal<T, K> {
|
||||
impl<T, K> HashFixedDataInternal<T, K> {
|
||||
pub 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),
|
||||
(self as *const _ as usize + offset_of!(HashFixedDataInternal<T, K>, next)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hash bucket.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashBucketDataInternal<T, K> {
|
||||
@@ -30,11 +33,12 @@ pub struct HashBucketDataInternal<T, K> {
|
||||
impl<T, K> HashBucketDataInternal<T, K> {
|
||||
pub 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),
|
||||
(self as *const _ as usize + offset_of!(HashBucketDataInternal<T, K>, next)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hash table.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashAllocatedData<T, K> {
|
||||
@@ -45,11 +49,12 @@ pub struct HashAllocatedData<T, K> {
|
||||
impl<T, K> HashAllocatedData<T, K> {
|
||||
pub 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),
|
||||
(self as *const _ as usize + offset_of!(HashAllocatedData<T, K>, list)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hash table.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashUnallocatedData<T, K> {
|
||||
@@ -63,23 +68,24 @@ pub struct HashUnallocatedData<T, K> {
|
||||
impl<T, K> HashUnallocatedData<T, K> {
|
||||
pub 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),
|
||||
(self as *const _ as usize + offset_of!(HashUnallocatedData<T, K>, next)).into(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ui_key(&self, process: &Process) -> Result<K> {
|
||||
process.read_memory::<K>(
|
||||
(self as *const _ as usize) + offset_of!(HashUnallocatedData<T, K>, ui_key),
|
||||
(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]> {
|
||||
process.read_memory::<[HashBucketDataInternal<T, K>; 256]>(
|
||||
(self as *const _ as usize) + offset_of!(HashUnallocatedData<T, K>, block_list),
|
||||
(self as *const _ as usize + offset_of!(HashUnallocatedData<T, K>, block_list)).into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a hash bucket.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashBucket<T, K> {
|
||||
@@ -100,17 +106,20 @@ pub struct UtlMemoryPool {
|
||||
}
|
||||
|
||||
impl UtlMemoryPool {
|
||||
/// Returns the number of blocks per blob.
|
||||
#[inline]
|
||||
pub fn block_size(&self) -> i32 {
|
||||
self.blocks_per_blob
|
||||
}
|
||||
|
||||
/// Returns the number of blocks allocated.
|
||||
#[inline]
|
||||
pub fn count(&self) -> i32 {
|
||||
self.block_allocated_size
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a thread-safe hash table.
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct UtlTsHash<T, K = u64> {
|
||||
@@ -122,16 +131,19 @@ impl<T, K> UtlTsHash<T, K>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
/// Returns the number of blocks per blob.
|
||||
#[inline]
|
||||
pub fn block_size(&self) -> i32 {
|
||||
self.entry_memory.block_size()
|
||||
}
|
||||
|
||||
/// Returns the number of blocks allocated.
|
||||
#[inline]
|
||||
pub fn count(&self) -> i32 {
|
||||
self.entry_memory.count()
|
||||
}
|
||||
|
||||
/// Returns a list of elements in the hash table.
|
||||
pub fn elements(&self, process: &Process) -> Result<Vec<T>> {
|
||||
let min_size = (self.block_size() as usize).min(self.count() as usize);
|
||||
|
||||
|
Reference in New Issue
Block a user