Rewrote project in Rust

This commit is contained in:
a2x
2023-09-26 00:46:10 +10:00
parent a8d3318d94
commit 369ebcf238
136 changed files with 47374 additions and 47187 deletions

13
src/sdk/mod.rs Normal file
View 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;

View File

@@ -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);
}
}

View 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)
}
}

View File

@@ -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);
}
}
}

View 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)
}
}

View File

@@ -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
View 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)
}
}

View File

@@ -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);
}
}

View 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)
}
}

View File

@@ -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);
}
}

View 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
View 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)
}
}