mirror of
https://github.com/a2x/cs2-dumper.git
synced 2025-10-07 16:30:01 +08:00
Ref #20
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
use std::ffi::c_char;
|
||||
use std::mem::offset_of;
|
||||
|
||||
use crate::builder::FileBuilderEnum;
|
||||
use crate::dumpers::Entry;
|
||||
use crate::error::Result;
|
||||
@@ -5,12 +8,44 @@ use crate::remote::Process;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
let module = process.get_module_by_name(&module_name)?;
|
||||
|
||||
if let Some(create_interface_export) = module.export("CreateInterface") {
|
||||
@@ -19,37 +54,32 @@ pub fn dump_interfaces(builders: &mut Vec<FileBuilderEnum>, process: &Process) -
|
||||
let create_interface_address =
|
||||
process.resolve_rip(create_interface_export.va, None, None)?;
|
||||
|
||||
let mut interface_registry_ptr = process
|
||||
.read_memory::<usize>(create_interface_address)
|
||||
.unwrap_or(0);
|
||||
if let Ok(mut interface_reg) =
|
||||
process.read_memory::<*mut InterfaceReg>(create_interface_address)
|
||||
{
|
||||
while !interface_reg.is_null() {
|
||||
let ptr = unsafe { (*interface_reg).ptr(process) }?;
|
||||
let name = unsafe { (*interface_reg).name(process) }?;
|
||||
|
||||
while interface_registry_ptr != 0 {
|
||||
let interface_ptr = process.read_memory::<usize>(interface_registry_ptr)?;
|
||||
log::debug!(
|
||||
" └─ {} @ {:#X} ({} + {:#X})",
|
||||
name,
|
||||
ptr,
|
||||
module_name,
|
||||
ptr - module.base()
|
||||
);
|
||||
|
||||
let interface_version_ptr =
|
||||
process.read_memory::<usize>(interface_registry_ptr + 0x8)?;
|
||||
entries
|
||||
.entry(module_name.replace(".", "_"))
|
||||
.or_default()
|
||||
.push(Entry {
|
||||
name: name.clone(),
|
||||
value: ptr - module.base(),
|
||||
comment: None,
|
||||
});
|
||||
|
||||
let interface_version = process.read_string(interface_version_ptr)?;
|
||||
|
||||
log::debug!(
|
||||
" └─ {} @ {:#X} ({} + {:#X})",
|
||||
interface_version,
|
||||
interface_ptr,
|
||||
module_name,
|
||||
interface_ptr - module.base()
|
||||
);
|
||||
|
||||
entries
|
||||
.entry(module_name.replace(".", "_"))
|
||||
.or_default()
|
||||
.push(Entry {
|
||||
name: interface_version.clone(),
|
||||
value: interface_ptr - module.base(),
|
||||
comment: None,
|
||||
});
|
||||
|
||||
interface_registry_ptr =
|
||||
process.read_memory::<usize>(interface_registry_ptr + 0x10)?;
|
||||
interface_reg = unsafe { (*interface_reg).next(process) }?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ pub fn generate_file(
|
||||
if builder.extension() != "json" {
|
||||
write!(
|
||||
file,
|
||||
"// Created using https://github.com/a2x/cs2-dumper\n// {}\n\n",
|
||||
"/*\n * https://github.com/a2x/cs2-dumper\n * {}\n */\n\n",
|
||||
chrono::Utc::now()
|
||||
)?;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
#![feature(offset_of)]
|
||||
|
||||
use std::fs;
|
||||
use std::time::Instant;
|
||||
|
@@ -1,86 +1,102 @@
|
||||
use std::mem::offset_of;
|
||||
|
||||
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,
|
||||
pub struct HashFixedDataInternal<T, K> {
|
||||
ui_key: K, // 0x0010
|
||||
next: *mut HashFixedDataInternal<T, K>, // 0x0010
|
||||
data: T, // 0x0010
|
||||
}
|
||||
|
||||
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)
|
||||
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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashFixedDataInternal<T, K> {
|
||||
ui_key: K,
|
||||
pad_0: [u8; 8],
|
||||
data: T,
|
||||
pub struct HashBucketDataInternal<T, K> {
|
||||
data: T, // 0x0000
|
||||
next: *mut HashFixedDataInternal<T, K>, // 0x0008
|
||||
ui_key: K, // 0x0010
|
||||
}
|
||||
|
||||
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)
|
||||
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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashAllocatedData<T, K> {
|
||||
list: [HashFixedDataInternal<T, K>; 128],
|
||||
pad_0: [u8; 0x18], // 0x0000
|
||||
list: [HashFixedDataInternal<T, K>; 128], // 0x0018
|
||||
}
|
||||
|
||||
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)
|
||||
process.read_memory::<[HashFixedDataInternal<T, K>; 128]>(
|
||||
(self as *const _ as usize) + offset_of!(HashAllocatedData<T, K>, list),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct HashUnallocatedData<T, K> {
|
||||
block_list: [HashBucketDataInternal<T, K>; 256],
|
||||
next: *mut HashUnallocatedData<T, K>, // 0x0000
|
||||
unknown_1: K, // 0x0008
|
||||
ui_key: K, // 0x0010
|
||||
unknown_2: K, // 0x0018
|
||||
block_list: [HashBucketDataInternal<T, K>; 256], // 0x0020
|
||||
}
|
||||
|
||||
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 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),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ui_key(&self, process: &Process) -> Result<K> {
|
||||
process.read_memory::<K>((self as *const _ as usize) + 0x10)
|
||||
process.read_memory::<K>(
|
||||
(self as *const _ as usize) + offset_of!(HashUnallocatedData<T, K>, ui_key),
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
process.read_memory::<[HashBucketDataInternal<T, K>; 256]>(
|
||||
(self as *const _ as usize) + offset_of!(HashUnallocatedData<T, K>, block_list),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[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>,
|
||||
pad_0: [u8; 0x10], // 0x0000
|
||||
allocated_data: *const HashAllocatedData<T, K>, // 0x0010
|
||||
unallocated_data: *const HashUnallocatedData<T, K>, // 0x0018
|
||||
}
|
||||
|
||||
#[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,
|
||||
block_size: i32, // 0x0000
|
||||
blocks_per_blob: i32, // 0x0004
|
||||
grow_mode: i32, // 0x0008
|
||||
blocks_allocated: i32, // 0x000C
|
||||
block_allocated_size: i32, // 0x0010
|
||||
peak_alloc: i32, // 0x0014
|
||||
}
|
||||
|
||||
impl UtlMemoryPool {
|
||||
@@ -98,8 +114,8 @@ impl UtlMemoryPool {
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct UtlTsHash<T, K = u64> {
|
||||
entry_memory: UtlMemoryPool,
|
||||
buckets: HashBucket<T, K>,
|
||||
entry_memory: UtlMemoryPool, // 0x0000
|
||||
buckets: HashBucket<T, K>, // 0x0018
|
||||
}
|
||||
|
||||
impl<T, K> UtlTsHash<T, K>
|
||||
@@ -124,19 +140,17 @@ where
|
||||
let mut address = self.buckets.unallocated_data;
|
||||
|
||||
while !address.is_null() {
|
||||
unsafe {
|
||||
let block_list = (*address).block_list(process)?;
|
||||
let block_list = unsafe { (*address).block_list(process) }?;
|
||||
|
||||
for i in 0..min_size {
|
||||
list.push(block_list[i].data);
|
||||
for i in 0..min_size {
|
||||
list.push(block_list[i].data);
|
||||
|
||||
if list.len() >= self.count() as usize {
|
||||
return Ok(list);
|
||||
}
|
||||
if list.len() >= self.count() as usize {
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
address = (*address).next(process)?;
|
||||
}
|
||||
|
||||
address = unsafe { (*address).next(process) }?;
|
||||
}
|
||||
|
||||
Ok(list)
|
||||
|
Reference in New Issue
Block a user