mirror of
https://github.com/a2x/cs2-dumper.git
synced 2025-10-07 22:50:03 +08:00
Rewrote project in Rust
This commit is contained in:
13
src/sdk/mod.rs
Normal file
13
src/sdk/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
pub use schema_class_field_data::SchemaClassFieldData;
|
||||
pub use schema_class_info::SchemaClassInfo;
|
||||
pub use schema_system::SchemaSystem;
|
||||
pub use schema_system_type_scope::SchemaSystemTypeScope;
|
||||
pub use schema_type_declared_class::SchemaTypeDeclaredClass;
|
||||
pub use utl_ts_hash::UtlTsHash;
|
||||
|
||||
pub mod schema_class_field_data;
|
||||
pub mod schema_class_info;
|
||||
pub mod schema_system;
|
||||
pub mod schema_system_type_scope;
|
||||
pub mod schema_type_declared_class;
|
||||
pub mod utl_ts_hash;
|
@@ -1,11 +0,0 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
std::string SchemaClassFieldData::name() const noexcept {
|
||||
return process::read_string(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this)), 64);
|
||||
}
|
||||
|
||||
std::uint16_t SchemaClassFieldData::offset() const noexcept {
|
||||
return process::read_memory<std::uint16_t>(reinterpret_cast<std::uint64_t>(this) + 0x10);
|
||||
}
|
||||
}
|
23
src/sdk/schema_class_field_data.rs
Normal file
23
src/sdk/schema_class_field_data.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use crate::error::Result;
|
||||
use crate::remote::Process;
|
||||
|
||||
pub struct SchemaClassFieldData<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
}
|
||||
|
||||
impl<'a> SchemaClassFieldData<'a> {
|
||||
pub fn new(process: &'a Process, address: usize) -> Self {
|
||||
Self { process, address }
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address)?;
|
||||
|
||||
self.process.read_string(name_ptr, 64)
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> Result<u16> {
|
||||
self.process.read_memory::<u16>(self.address + 0x10)
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
std::uint16_t SchemaClassInfo::fields_count() const noexcept {
|
||||
return process::read_memory<std::uint16_t>(reinterpret_cast<std::uint64_t>(this) + 0x1C);
|
||||
}
|
||||
|
||||
void SchemaClassInfo::for_each_field(const std::function<void(SchemaClassFieldData*)>& callback) const noexcept {
|
||||
for (std::size_t i = 0; i < fields_count(); ++i) {
|
||||
const auto field = reinterpret_cast<SchemaClassFieldData*>(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x28) + (i * 0x20));
|
||||
|
||||
if (field == nullptr)
|
||||
continue;
|
||||
|
||||
callback(field);
|
||||
}
|
||||
}
|
||||
}
|
47
src/sdk/schema_class_info.rs
Normal file
47
src/sdk/schema_class_info.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use crate::error::Result;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaClassFieldData;
|
||||
|
||||
pub struct SchemaClassInfo<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
class_name: String,
|
||||
}
|
||||
|
||||
impl<'a> SchemaClassInfo<'a> {
|
||||
pub fn new(process: &'a Process, address: usize, class_name: &str) -> Self {
|
||||
Self {
|
||||
process,
|
||||
address,
|
||||
class_name: class_name.into(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
&self.class_name
|
||||
}
|
||||
|
||||
pub fn fields(&self) -> Result<Vec<SchemaClassFieldData>> {
|
||||
let count = self.fields_count()?;
|
||||
|
||||
let fields: Vec<SchemaClassFieldData> = (0..count as usize)
|
||||
.filter_map(|i| {
|
||||
let field = self
|
||||
.process
|
||||
.read_memory::<usize>(self.address + 0x28)
|
||||
.ok()?
|
||||
+ (i * 0x20);
|
||||
|
||||
(field != 0).then(|| SchemaClassFieldData::new(self.process, field))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(fields)
|
||||
}
|
||||
|
||||
pub fn fields_count(&self) -> Result<u16> {
|
||||
self.process.read_memory::<u16>(self.address + 0x1C)
|
||||
}
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
SchemaSystem* SchemaSystem::get() noexcept {
|
||||
const auto 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");
|
||||
|
||||
if (!address.has_value())
|
||||
return nullptr;
|
||||
|
||||
return address->rip().as<SchemaSystem*>();
|
||||
}
|
||||
|
||||
std::vector<SchemaSystemTypeScope*> SchemaSystem::type_scopes() const noexcept {
|
||||
const auto count = process::read_memory<std::uint32_t>(reinterpret_cast<std::uint64_t>(this) + 0x190);
|
||||
const auto data = process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x198);
|
||||
|
||||
if (count == 0 || data == 0)
|
||||
return {};
|
||||
|
||||
std::vector<sdk::SchemaSystemTypeScope*> type_scopes;
|
||||
|
||||
type_scopes.resize(count);
|
||||
|
||||
process::read_memory(data, type_scopes.data(), count * sizeof(std::uint64_t));
|
||||
|
||||
return type_scopes;
|
||||
}
|
||||
}
|
42
src/sdk/schema_system.rs
Normal file
42
src/sdk/schema_system.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use crate::error::Result;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::SchemaSystemTypeScope;
|
||||
|
||||
pub struct SchemaSystem<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
}
|
||||
|
||||
impl<'a> SchemaSystem<'a> {
|
||||
pub fn new(process: &'a Process) -> Result<Self> {
|
||||
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"
|
||||
)?;
|
||||
|
||||
address = process.resolve_relative(address)?;
|
||||
|
||||
Ok(Self { process, address })
|
||||
}
|
||||
|
||||
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 mut addresses: Vec<usize> = vec![0; size as usize];
|
||||
|
||||
self.process.read_memory_raw(
|
||||
data,
|
||||
addresses.as_mut_ptr() as *mut _,
|
||||
addresses.len() * std::mem::size_of::<usize>(),
|
||||
)?;
|
||||
|
||||
let type_scopes: Vec<SchemaSystemTypeScope> = addresses
|
||||
.iter()
|
||||
.map(|&address| SchemaSystemTypeScope::new(self.process, address))
|
||||
.collect();
|
||||
|
||||
Ok(type_scopes)
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
void SchemaSystemTypeScope::for_each_class(const std::function<void(std::pair<std::string, SchemaClassInfo*>)>& callback) const noexcept {
|
||||
const auto classes = process::read_memory<UtlTsHash<SchemaTypeDeclaredClass*>>(reinterpret_cast<std::uint64_t>(this) + 0x588);
|
||||
|
||||
for (const auto& element : classes.elements())
|
||||
callback({ element->binary_name(), reinterpret_cast<SchemaClassInfo*>(element) });
|
||||
}
|
||||
|
||||
std::string SchemaSystemTypeScope::module_name() const noexcept {
|
||||
return process::read_string(reinterpret_cast<std::uint64_t>(this) + 0x8, 256);
|
||||
}
|
||||
}
|
40
src/sdk/schema_system_type_scope.rs
Normal file
40
src/sdk/schema_system_type_scope.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use crate::error::Result;
|
||||
use crate::remote::Process;
|
||||
|
||||
use super::{SchemaClassInfo, SchemaTypeDeclaredClass, UtlTsHash};
|
||||
|
||||
pub struct SchemaSystemTypeScope<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
}
|
||||
|
||||
impl<'a> SchemaSystemTypeScope<'a> {
|
||||
pub fn new(process: &'a Process, address: usize) -> Self {
|
||||
Self { process, address }
|
||||
}
|
||||
|
||||
pub fn classes(&self) -> Result<Vec<SchemaClassInfo>> {
|
||||
let classes = self
|
||||
.process
|
||||
.read_memory::<UtlTsHash<*mut SchemaTypeDeclaredClass>>(self.address + 0x588)?;
|
||||
|
||||
let classes: Vec<SchemaClassInfo> = classes
|
||||
.elements(self.process)?
|
||||
.iter()
|
||||
.filter_map(|&address| {
|
||||
let declared_class = SchemaTypeDeclaredClass::new(self.process, address as usize);
|
||||
|
||||
declared_class
|
||||
.name()
|
||||
.ok()
|
||||
.map(|name| SchemaClassInfo::new(self.process, address as usize, &name))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(classes)
|
||||
}
|
||||
|
||||
pub fn module_name(&self) -> Result<String> {
|
||||
self.process.read_string(self.address + 0x8, 256)
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
#include "sdk/sdk.hpp"
|
||||
|
||||
namespace sdk {
|
||||
std::string SchemaTypeDeclaredClass::binary_name() const noexcept {
|
||||
return process::read_string(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x8), 64);
|
||||
}
|
||||
|
||||
std::string SchemaTypeDeclaredClass::module_name() const noexcept {
|
||||
return process::read_string(process::read_memory<std::uint64_t>(reinterpret_cast<std::uint64_t>(this) + 0x10), 256);
|
||||
}
|
||||
}
|
19
src/sdk/schema_type_declared_class.rs
Normal file
19
src/sdk/schema_type_declared_class.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use crate::error::Result;
|
||||
use crate::remote::Process;
|
||||
|
||||
pub struct SchemaTypeDeclaredClass<'a> {
|
||||
process: &'a Process,
|
||||
address: usize,
|
||||
}
|
||||
|
||||
impl<'a> SchemaTypeDeclaredClass<'a> {
|
||||
pub fn new(process: &'a Process, address: usize) -> Self {
|
||||
Self { process, address }
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Result<String> {
|
||||
let name_ptr = self.process.read_memory::<usize>(self.address + 0x8)?;
|
||||
|
||||
self.process.read_string(name_ptr, 64)
|
||||
}
|
||||
}
|
144
src/sdk/utl_ts_hash.rs
Normal file
144
src/sdk/utl_ts_hash.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
use crate::error::Result;
|
||||
use crate::remote::Process;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashBucketDataInternal<T, K> {
|
||||
data: T,
|
||||
pad_0: [u8; 8],
|
||||
ui_key: K,
|
||||
}
|
||||
|
||||
impl<T, K> HashBucketDataInternal<T, K> {
|
||||
pub fn next(&self, process: &Process) -> Result<*const HashBucketDataInternal<T, K>> {
|
||||
process
|
||||
.read_memory::<*const HashBucketDataInternal<T, K>>((self as *const _ as usize) + 0x8)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashFixedDataInternal<T, K> {
|
||||
ui_key: K,
|
||||
pad_0: [u8; 8],
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T, K> HashFixedDataInternal<T, K> {
|
||||
pub fn next(&self, process: &Process) -> Result<*const HashFixedDataInternal<T, K>> {
|
||||
process.read_memory::<*const HashFixedDataInternal<T, K>>((self as *const _ as usize) + 0x8)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashAllocatedData<T, K> {
|
||||
list: [HashFixedDataInternal<T, K>; 128],
|
||||
}
|
||||
|
||||
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) + 0x18)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashUnallocatedData<T, K> {
|
||||
block_list: [HashBucketDataInternal<T, K>; 256],
|
||||
}
|
||||
|
||||
impl<T, K> HashUnallocatedData<T, K> {
|
||||
pub fn next(&self, process: &Process) -> Result<*const HashUnallocatedData<T, K>> {
|
||||
process.read_memory::<*const HashUnallocatedData<T, K>>(self as *const _ as usize)
|
||||
}
|
||||
|
||||
pub fn ui_key(&self, process: &Process) -> Result<K> {
|
||||
process.read_memory::<K>((self as *const _ as usize) + 0x10)
|
||||
}
|
||||
|
||||
pub fn block_list(&self, process: &Process) -> Result<[HashBucketDataInternal<T, K>; 256]> {
|
||||
process
|
||||
.read_memory::<[HashBucketDataInternal<T, K>; 256]>((self as *const _ as usize) + 0x20)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashBucket<T, K> {
|
||||
pad_0: [u8; 16],
|
||||
allocated_data: *const HashAllocatedData<T, K>,
|
||||
unallocated_data: *const HashUnallocatedData<T, K>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct UtlMemoryPool {
|
||||
block_size: i32,
|
||||
blocks_per_blob: i32,
|
||||
grow_mode: i32,
|
||||
blocks_allocated: i32,
|
||||
block_allocated_size: i32,
|
||||
peak_alloc: i32,
|
||||
}
|
||||
|
||||
impl UtlMemoryPool {
|
||||
#[inline]
|
||||
pub fn block_size(&self) -> i32 {
|
||||
self.blocks_per_blob
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn count(&self) -> i32 {
|
||||
self.block_allocated_size
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct UtlTsHash<T, K = u64> {
|
||||
entry_memory: UtlMemoryPool,
|
||||
buckets: HashBucket<T, K>,
|
||||
}
|
||||
|
||||
impl<T, K> UtlTsHash<T, K>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
#[inline]
|
||||
pub fn block_size(&self) -> i32 {
|
||||
self.entry_memory.block_size()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn count(&self) -> i32 {
|
||||
self.entry_memory.count()
|
||||
}
|
||||
|
||||
pub fn elements(&self, process: &Process) -> Result<Vec<T>> {
|
||||
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() {
|
||||
unsafe {
|
||||
let block_list = (*address).block_list(process)?;
|
||||
|
||||
for i in 0..min_size {
|
||||
list.push(block_list[i].data);
|
||||
|
||||
if list.len() >= self.count() as usize {
|
||||
return Ok(list);
|
||||
}
|
||||
}
|
||||
|
||||
address = (*address).next(process)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user