mirror of
https://github.com/a2x/cs2-dumper.git
synced 2025-04-23 11:45:34 +08:00
Simplify some code
This commit is contained in:
parent
c791a97d3b
commit
a538968730
5
cs2-dumper.log
Normal file
5
cs2-dumper.log
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
13:06:03 [INFO] found 16 buttons
|
||||||
|
13:06:03 [INFO] found 130 interfaces across 33 modules
|
||||||
|
13:06:04 [INFO] found 33 offsets across 5 modules
|
||||||
|
13:06:04 [INFO] found 2468 classes and 368 enums across 17 modules
|
||||||
|
13:06:04 [INFO] analysis completed in 1.02s
|
@ -1,6 +1,6 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{Result, bail};
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ use crate::source2::KeyButton;
|
|||||||
|
|
||||||
pub type ButtonMap = BTreeMap<String, imem>;
|
pub type ButtonMap = BTreeMap<String, imem>;
|
||||||
|
|
||||||
pub fn buttons(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<ButtonMap> {
|
pub fn buttons<P: Process + MemoryView>(process: &mut P) -> Result<ButtonMap> {
|
||||||
let module = process.module_by_name("client.dll")?;
|
let module = process.module_by_name("client.dll")?;
|
||||||
|
|
||||||
let buf = process
|
let buf = process
|
||||||
@ -35,17 +35,17 @@ pub fn buttons(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<ButtonMap>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_buttons(
|
fn read_buttons(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
module: &ModuleInfo,
|
module: &ModuleInfo,
|
||||||
list_addr: Address,
|
list_addr: Address,
|
||||||
) -> Result<ButtonMap> {
|
) -> Result<ButtonMap> {
|
||||||
let mut map = ButtonMap::new();
|
let mut map = ButtonMap::new();
|
||||||
|
|
||||||
let mut cur_button = Pointer64::<KeyButton>::from(process.read_addr64(list_addr).data_part()?);
|
let mut cur_button = Pointer64::<KeyButton>::from(mem.read_addr64(list_addr).data_part()?);
|
||||||
|
|
||||||
while !cur_button.is_null() {
|
while !cur_button.is_null() {
|
||||||
let button = process.read_ptr(cur_button).data_part()?;
|
let button = mem.read_ptr(cur_button).data_part()?;
|
||||||
let name = process.read_utf8(button.name.address(), 32).data_part()?;
|
let name = mem.read_utf8(button.name.address(), 32).data_part()?;
|
||||||
let rva = (cur_button.address() - module.base) + offset_of!(KeyButton.state) as imem;
|
let rva = (cur_button.address() - module.base) + offset_of!(KeyButton.state) as imem;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -9,20 +9,16 @@ use memflow::prelude::v1::*;
|
|||||||
use pelite::pe64::exports::Export;
|
use pelite::pe64::exports::Export;
|
||||||
use pelite::pe64::{Pe, PeView};
|
use pelite::pe64::{Pe, PeView};
|
||||||
|
|
||||||
use crate::mem::read_addr64_rip;
|
|
||||||
use crate::source2::InterfaceReg;
|
use crate::source2::InterfaceReg;
|
||||||
|
|
||||||
pub type InterfaceMap = BTreeMap<String, BTreeMap<String, umem>>;
|
pub type InterfaceMap = BTreeMap<String, BTreeMap<String, umem>>;
|
||||||
|
|
||||||
pub fn interfaces(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<InterfaceMap> {
|
pub fn interfaces<P: Process + MemoryView>(process: &mut P) -> Result<InterfaceMap> {
|
||||||
process
|
process
|
||||||
.module_list()?
|
.module_list()?
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|module| module.name.as_ref() != "crashandler64.dll")
|
||||||
.filter_map(|module| {
|
.filter_map(|module| {
|
||||||
if module.name.as_ref() == "crashhandler64.dll" {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let buf = process
|
let buf = process
|
||||||
.read_raw(module.base, module.size as _)
|
.read_raw(module.base, module.size as _)
|
||||||
.data_part()
|
.data_part()
|
||||||
@ -39,9 +35,7 @@ pub fn interfaces(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Interfa
|
|||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
if let Export::Symbol(symbol) = ci_export {
|
if let Export::Symbol(symbol) = ci_export {
|
||||||
let list_addr = read_addr64_rip(process, module.base + symbol)
|
let list_addr = read_addr64_rip(process, module.base + symbol).ok()?;
|
||||||
.data_part()
|
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
return read_interfaces(process, module, list_addr)
|
return read_interfaces(process, module, list_addr)
|
||||||
.ok()
|
.ok()
|
||||||
@ -55,18 +49,18 @@ pub fn interfaces(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Interfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_interfaces(
|
fn read_interfaces(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
module: &ModuleInfo,
|
module: &ModuleInfo,
|
||||||
list_addr: Address,
|
list_addr: Address,
|
||||||
) -> Result<BTreeMap<String, umem>> {
|
) -> Result<BTreeMap<String, umem>> {
|
||||||
let mut ifaces = BTreeMap::new();
|
let mut ifaces = BTreeMap::new();
|
||||||
|
|
||||||
let mut cur_reg = Pointer64::<InterfaceReg>::from(process.read_addr64(list_addr).data_part()?);
|
let mut cur_reg = Pointer64::<InterfaceReg>::from(mem.read_addr64(list_addr).data_part()?);
|
||||||
|
|
||||||
while !cur_reg.is_null() {
|
while !cur_reg.is_null() {
|
||||||
let reg = process.read_ptr(cur_reg).data_part()?;
|
let reg = mem.read_ptr(cur_reg).data_part()?;
|
||||||
let name = process.read_utf8(reg.name.address(), 128).data_part()?;
|
let name = mem.read_utf8(reg.name.address(), 128).data_part()?;
|
||||||
let instance = read_addr64_rip(process, reg.create_fn.address())?;
|
let instance = read_addr64_rip(mem, reg.create_fn.address())?;
|
||||||
let value = instance.wrapping_sub(module.base).to_umem();
|
let value = instance.wrapping_sub(module.base).to_umem();
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
@ -84,3 +78,9 @@ fn read_interfaces(
|
|||||||
|
|
||||||
Ok(ifaces)
|
Ok(ifaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_addr64_rip(mem: &mut impl MemoryView, addr: Address) -> Result<Address> {
|
||||||
|
let disp = mem.read::<i32>(addr + 0x3).data_part()?;
|
||||||
|
|
||||||
|
Ok(addr + 0x7 + disp)
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ pub struct AnalysisResult {
|
|||||||
pub schemas: SchemaMap,
|
pub schemas: SchemaMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyze_all(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<AnalysisResult> {
|
pub fn analyze_all<P: Process + MemoryView>(process: &mut P) -> Result<AnalysisResult> {
|
||||||
let buttons = analyze(process, buttons);
|
let buttons = analyze(process, buttons);
|
||||||
|
|
||||||
info!("found {} buttons", buttons.len());
|
info!("found {} buttons", buttons.len());
|
||||||
@ -75,10 +75,10 @@ pub fn analyze_all(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Analys
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn analyze<P, F, T>(process: &mut P, f: F) -> T
|
||||||
fn analyze<F, T>(process: &mut IntoProcessInstanceArcBox<'_>, f: F) -> T
|
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut IntoProcessInstanceArcBox<'_>) -> Result<T>,
|
P: Process + MemoryView,
|
||||||
|
F: FnOnce(&mut P) -> Result<T>,
|
||||||
T: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
let name = type_name::<F>();
|
let name = type_name::<F>();
|
||||||
|
@ -7,10 +7,10 @@ use log::{debug, error};
|
|||||||
use memflow::prelude::v1::*;
|
use memflow::prelude::v1::*;
|
||||||
|
|
||||||
use pelite::pattern;
|
use pelite::pattern;
|
||||||
use pelite::pattern::{save_len, Atom};
|
use pelite::pattern::{Atom, save_len};
|
||||||
use pelite::pe64::{Pe, PeView, Rva};
|
use pelite::pe64::{Pe, PeView, Rva};
|
||||||
|
|
||||||
use phf::{phf_map, Map};
|
use phf::{Map, phf_map};
|
||||||
|
|
||||||
pub type OffsetMap = BTreeMap<String, BTreeMap<String, Rva>>;
|
pub type OffsetMap = BTreeMap<String, BTreeMap<String, Rva>>;
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ pattern_map! {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offsets(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<OffsetMap> {
|
pub fn offsets<P: Process + MemoryView>(process: &mut P) -> Result<OffsetMap> {
|
||||||
let mut map = BTreeMap::new();
|
let mut map = BTreeMap::new();
|
||||||
|
|
||||||
let modules: [(&str, fn(PeView) -> BTreeMap<String, u32>); 5] = [
|
let modules: [(&str, fn(PeView) -> BTreeMap<String, u32>); 5] = [
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{Result, bail};
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ pub struct TypeScope {
|
|||||||
pub enums: Vec<Enum>,
|
pub enums: Vec<Enum>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schemas(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<SchemaMap> {
|
pub fn schemas<P: Process + MemoryView>(process: &mut P) -> Result<SchemaMap> {
|
||||||
let schema_system = read_schema_system(process)?;
|
let schema_system = read_schema_system(process)?;
|
||||||
let type_scopes = read_type_scopes(process, &schema_system)?;
|
let type_scopes = read_type_scopes(process, &schema_system)?;
|
||||||
|
|
||||||
@ -78,17 +78,17 @@ pub fn schemas(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<SchemaMap>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_class_binding(
|
fn read_class_binding(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
binding_ptr: Pointer64<SchemaClassBinding>,
|
binding_ptr: Pointer64<SchemaClassBinding>,
|
||||||
) -> Result<Class> {
|
) -> Result<Class> {
|
||||||
let binding = process.read_ptr(binding_ptr).data_part()?;
|
let binding = mem.read_ptr(binding_ptr).data_part()?;
|
||||||
|
|
||||||
let module_name = process
|
let module_name = mem
|
||||||
.read_utf8_lossy(binding.module_name.address(), 128)
|
.read_utf8_lossy(binding.module_name.address(), 128)
|
||||||
.data_part()
|
.data_part()
|
||||||
.map(|s| format!("{}.dll", s))?;
|
.map(|s| format!("{}.dll", s))?;
|
||||||
|
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(binding.name.address(), 4096)
|
.read_utf8_lossy(binding.name.address(), 4096)
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
@ -97,15 +97,15 @@ fn read_class_binding(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let parent = binding.base_classes.non_null().and_then(|ptr| {
|
let parent = binding.base_classes.non_null().and_then(|ptr| {
|
||||||
let base_class = process.read_ptr(ptr).data_part().ok()?;
|
let base_class = mem.read_ptr(ptr).data_part().ok()?;
|
||||||
let parent_class = process.read_ptr(base_class.prev).data_part().ok()?;
|
let parent_class = mem.read_ptr(base_class.prev).data_part().ok()?;
|
||||||
|
|
||||||
let module_name = process
|
let module_name = mem
|
||||||
.read_utf8_lossy(parent_class.module_name.address(), 128)
|
.read_utf8_lossy(parent_class.module_name.address(), 128)
|
||||||
.data_part()
|
.data_part()
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(parent_class.name.address(), 4096)
|
.read_utf8_lossy(parent_class.name.address(), 4096)
|
||||||
.data_part()
|
.data_part()
|
||||||
.ok()?;
|
.ok()?;
|
||||||
@ -119,8 +119,8 @@ fn read_class_binding(
|
|||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
let fields = read_class_binding_fields(process, &binding)?;
|
let fields = read_class_binding_fields(mem, &binding)?;
|
||||||
let metadata = read_class_binding_metadata(process, &binding)?;
|
let metadata = read_class_binding_metadata(mem, &binding)?;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"found class: {} at {:#X} (module name: {}) (parent name: {:?}) (metadata count: {}) (field count: {})",
|
"found class: {} at {:#X} (module name: {}) (parent name: {:?}) (metadata count: {}) (field count: {})",
|
||||||
@ -142,7 +142,7 @@ fn read_class_binding(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_class_binding_fields(
|
fn read_class_binding_fields(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
binding: &SchemaClassBinding,
|
binding: &SchemaClassBinding,
|
||||||
) -> Result<Vec<ClassField>> {
|
) -> Result<Vec<ClassField>> {
|
||||||
if binding.fields.is_null() {
|
if binding.fields.is_null() {
|
||||||
@ -150,28 +150,28 @@ fn read_class_binding_fields(
|
|||||||
}
|
}
|
||||||
|
|
||||||
(0..binding.field_count).try_fold(Vec::new(), |mut acc, i| {
|
(0..binding.field_count).try_fold(Vec::new(), |mut acc, i| {
|
||||||
let field = process.read_ptr(binding.fields.at(i as _)).data_part()?;
|
let field = mem.read_ptr(binding.fields.at(i as _)).data_part()?;
|
||||||
|
|
||||||
if field.schema_type.is_null() {
|
if field.r#type.is_null() {
|
||||||
return Ok(acc);
|
return Ok(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(field.name.address(), 4096)
|
.read_utf8_lossy(field.name.address(), 4096)
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
let schema_type = process.read_ptr(field.schema_type).data_part()?;
|
let r#type = mem.read_ptr(field.r#type).data_part()?;
|
||||||
|
|
||||||
// TODO: Parse this properly.
|
// TODO: Parse this properly.
|
||||||
let type_name = process
|
let type_name = mem
|
||||||
.read_utf8_lossy(schema_type.name.address(), 128)
|
.read_utf8_lossy(r#type.name.address(), 128)
|
||||||
.data_part()?
|
.data_part()?
|
||||||
.replace(" ", "");
|
.replace(" ", "");
|
||||||
|
|
||||||
acc.push(ClassField {
|
acc.push(ClassField {
|
||||||
name,
|
name,
|
||||||
type_name,
|
type_name,
|
||||||
offset: field.single_inheritance_offset,
|
offset: field.offset,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
@ -179,7 +179,7 @@ fn read_class_binding_fields(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_class_binding_metadata(
|
fn read_class_binding_metadata(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
binding: &SchemaClassBinding,
|
binding: &SchemaClassBinding,
|
||||||
) -> Result<Vec<ClassMetadata>> {
|
) -> Result<Vec<ClassMetadata>> {
|
||||||
if binding.static_metadata.is_null() {
|
if binding.static_metadata.is_null() {
|
||||||
@ -187,7 +187,7 @@ fn read_class_binding_metadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
(0..binding.static_metadata_count).try_fold(Vec::new(), |mut acc, i| {
|
(0..binding.static_metadata_count).try_fold(Vec::new(), |mut acc, i| {
|
||||||
let metadata = process
|
let metadata = mem
|
||||||
.read_ptr(binding.static_metadata.at(i as _))
|
.read_ptr(binding.static_metadata.at(i as _))
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
@ -195,15 +195,15 @@ fn read_class_binding_metadata(
|
|||||||
return Ok(acc);
|
return Ok(acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(metadata.name.address(), 4096)
|
.read_utf8_lossy(metadata.name.address(), 4096)
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
let network_value = process.read_ptr(metadata.network_value).data_part()?;
|
let network_value = mem.read_ptr(metadata.network_value).data_part()?;
|
||||||
|
|
||||||
let metadata = match name.as_str() {
|
let metadata = match name.as_str() {
|
||||||
"MNetworkChangeCallback" => unsafe {
|
"MNetworkChangeCallback" => unsafe {
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(network_value.value.name_ptr.address(), 4096)
|
.read_utf8_lossy(network_value.value.name_ptr.address(), 4096)
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
@ -212,11 +212,11 @@ fn read_class_binding_metadata(
|
|||||||
"MNetworkVarNames" => unsafe {
|
"MNetworkVarNames" => unsafe {
|
||||||
let var_value = network_value.value.var_value;
|
let var_value = network_value.value.var_value;
|
||||||
|
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(var_value.name.address(), 4096)
|
.read_utf8_lossy(var_value.name.address(), 4096)
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
let type_name = process
|
let type_name = mem
|
||||||
.read_utf8_lossy(var_value.type_name.address(), 128)
|
.read_utf8_lossy(var_value.type_name.address(), 128)
|
||||||
.data_part()?
|
.data_part()?
|
||||||
.replace(" ", "");
|
.replace(" ", "");
|
||||||
@ -233,12 +233,12 @@ fn read_class_binding_metadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_enum_binding(
|
fn read_enum_binding(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
binding_ptr: Pointer64<SchemaEnumBinding>,
|
binding_ptr: Pointer64<SchemaEnumBinding>,
|
||||||
) -> Result<Enum> {
|
) -> Result<Enum> {
|
||||||
let binding = process.read_ptr(binding_ptr).data_part()?;
|
let binding = mem.read_ptr(binding_ptr).data_part()?;
|
||||||
|
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(binding.name.address(), 4096)
|
.read_utf8_lossy(binding.name.address(), 4096)
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ fn read_enum_binding(
|
|||||||
bail!("empty enum name");
|
bail!("empty enum name");
|
||||||
}
|
}
|
||||||
|
|
||||||
let members = read_enum_binding_members(process, &binding)?;
|
let members = read_enum_binding_members(mem, &binding)?;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"found enum: {} at {:#X} (alignment: {}) (member count: {})",
|
"found enum: {} at {:#X} (alignment: {}) (member count: {})",
|
||||||
@ -259,38 +259,36 @@ fn read_enum_binding(
|
|||||||
Ok(Enum {
|
Ok(Enum {
|
||||||
name,
|
name,
|
||||||
alignment: binding.align_of,
|
alignment: binding.align_of,
|
||||||
size: binding.enumerator_count,
|
size: binding.enum_count,
|
||||||
members,
|
members,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_enum_binding_members(
|
fn read_enum_binding_members(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
binding: &SchemaEnumBinding,
|
binding: &SchemaEnumBinding,
|
||||||
) -> Result<Vec<EnumMember>> {
|
) -> Result<Vec<EnumMember>> {
|
||||||
if binding.enumerators.is_null() {
|
if binding.enums.is_null() {
|
||||||
return Ok(Vec::new());
|
return Ok(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
(0..binding.enumerator_count).try_fold(Vec::new(), |mut acc, i| {
|
(0..binding.enum_count).try_fold(Vec::new(), |mut acc, i| {
|
||||||
let enumerator = process
|
let r#enum = mem.read_ptr(binding.enums.at(i as _)).data_part()?;
|
||||||
.read_ptr(binding.enumerators.at(i as _))
|
|
||||||
.data_part()?;
|
|
||||||
|
|
||||||
let name = process
|
let name = mem
|
||||||
.read_utf8_lossy(enumerator.name.address(), 4096)
|
.read_utf8_lossy(r#enum.name.address(), 4096)
|
||||||
.data_part()?;
|
.data_part()?;
|
||||||
|
|
||||||
acc.push(EnumMember {
|
acc.push(EnumMember {
|
||||||
name,
|
name,
|
||||||
value: unsafe { enumerator.value.ulong } as i64,
|
value: unsafe { r#enum.value.ulong } as i64,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(acc)
|
Ok(acc)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_schema_system(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<SchemaSystem> {
|
fn read_schema_system<P: Process + MemoryView>(process: &mut P) -> Result<SchemaSystem> {
|
||||||
let module = process.module_by_name("schemasystem.dll")?;
|
let module = process.module_by_name("schemasystem.dll")?;
|
||||||
|
|
||||||
let buf = process
|
let buf = process
|
||||||
@ -318,14 +316,14 @@ fn read_schema_system(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Sch
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_type_scopes(
|
fn read_type_scopes(
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
mem: &mut impl MemoryView,
|
||||||
schema_system: &SchemaSystem,
|
schema_system: &SchemaSystem,
|
||||||
) -> Result<Vec<TypeScope>> {
|
) -> Result<Vec<TypeScope>> {
|
||||||
let type_scopes = &schema_system.type_scopes;
|
let type_scopes = &schema_system.type_scopes;
|
||||||
|
|
||||||
(0..type_scopes.size).try_fold(Vec::new(), |mut acc, i| {
|
(0..type_scopes.size).try_fold(Vec::new(), |mut acc, i| {
|
||||||
let type_scope_ptr = type_scopes.element(process, i as _)?;
|
let type_scope_ptr = type_scopes.element(mem, i as _)?;
|
||||||
let type_scope = process.read_ptr(type_scope_ptr).data_part()?;
|
let type_scope = mem.read_ptr(type_scope_ptr).data_part()?;
|
||||||
|
|
||||||
let module_name = unsafe { CStr::from_ptr(type_scope.name.as_ptr()) }
|
let module_name = unsafe { CStr::from_ptr(type_scope.name.as_ptr()) }
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
@ -333,16 +331,16 @@ fn read_type_scopes(
|
|||||||
|
|
||||||
let classes: Vec<_> = type_scope
|
let classes: Vec<_> = type_scope
|
||||||
.class_bindings
|
.class_bindings
|
||||||
.elements(process)?
|
.elements(mem)?
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|ptr| read_class_binding(process, *ptr).ok())
|
.filter_map(|ptr| read_class_binding(mem, *ptr).ok())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let enums: Vec<_> = type_scope
|
let enums: Vec<_> = type_scope
|
||||||
.enum_bindings
|
.enum_bindings
|
||||||
.elements(process)?
|
.elements(mem)?
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|ptr| read_enum_binding(process, *ptr).ok())
|
.filter_map(|ptr| read_enum_binding(mem, *ptr).ok())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if classes.is_empty() && enums.is_empty() {
|
if classes.is_empty() && enums.is_empty() {
|
||||||
|
14
src/main.rs
14
src/main.rs
@ -5,20 +5,17 @@ use std::time::Instant;
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use clap::*;
|
use clap::{ArgAction, Parser};
|
||||||
|
|
||||||
use log::{info, LevelFilter};
|
use log::{LevelFilter, info};
|
||||||
|
|
||||||
use memflow::prelude::v1::*;
|
use memflow::prelude::v1::*;
|
||||||
|
|
||||||
use simplelog::{
|
use simplelog::*;
|
||||||
ColorChoice, CombinedLogger, Config, SharedLogger, TermLogger, TerminalMode, WriteLogger,
|
|
||||||
};
|
|
||||||
|
|
||||||
use output::Output;
|
use output::Output;
|
||||||
|
|
||||||
mod analysis;
|
mod analysis;
|
||||||
mod mem;
|
|
||||||
mod output;
|
mod output;
|
||||||
mod source2;
|
mod source2;
|
||||||
|
|
||||||
@ -92,7 +89,7 @@ fn main() -> Result<()> {
|
|||||||
.map(|s| ConnectorArgs::from_str(&s).expect("unable to parse connector arguments"))
|
.map(|s| ConnectorArgs::from_str(&s).expect("unable to parse connector arguments"))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let os = match args.connector {
|
let mut os = match args.connector {
|
||||||
Some(conn) => {
|
Some(conn) => {
|
||||||
let inventory = Inventory::scan();
|
let inventory = Inventory::scan();
|
||||||
|
|
||||||
@ -115,12 +112,11 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut process = os.into_process_by_name(&args.process_name)?;
|
let mut process = os.process_by_name(&args.process_name)?;
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
let result = analysis::analyze_all(&mut process)?;
|
let result = analysis::analyze_all(&mut process)?;
|
||||||
|
|
||||||
let output = Output::new(&args.file_types, args.indent_size, &args.output, &result)?;
|
let output = Output::new(&args.file_types, args.indent_size, &args.output, &result)?;
|
||||||
|
|
||||||
output.dump_all(&mut process)?;
|
output.dump_all(&mut process)?;
|
||||||
|
24
src/mem.rs
24
src/mem.rs
@ -1,24 +0,0 @@
|
|||||||
use memflow::prelude::v1::*;
|
|
||||||
|
|
||||||
pub trait PointerExt {
|
|
||||||
fn is_null(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<U: PrimitiveAddress, T> PointerExt for Pointer<U, T> {
|
|
||||||
#[inline]
|
|
||||||
fn is_null(&self) -> bool {
|
|
||||||
self.inner.is_null()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_addr64_rip(
|
|
||||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
|
||||||
addr: Address,
|
|
||||||
) -> PartialResult<Address> {
|
|
||||||
let displacement = match process.read::<i32>(addr + 0x3) {
|
|
||||||
Ok(d) => d,
|
|
||||||
Err(e) => return Err(PartialError::Error(e.into())),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(addr + 0x7 + displacement)
|
|
||||||
}
|
|
@ -3,7 +3,7 @@ use std::fmt::{self, Write};
|
|||||||
|
|
||||||
use heck::{AsPascalCase, AsSnakeCase};
|
use heck::{AsPascalCase, AsSnakeCase};
|
||||||
|
|
||||||
use super::{slugify, CodeWriter, Formatter, InterfaceMap};
|
use super::{CodeWriter, Formatter, InterfaceMap, slugify};
|
||||||
|
|
||||||
impl CodeWriter for InterfaceMap {
|
impl CodeWriter for InterfaceMap {
|
||||||
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
@ -17,7 +17,11 @@ impl CodeWriter for InterfaceMap {
|
|||||||
|fmt| {
|
|fmt| {
|
||||||
for (name, value) in ifaces {
|
for (name, value) in ifaces {
|
||||||
if *value > i32::MAX as u64 {
|
if *value > i32::MAX as u64 {
|
||||||
writeln!(fmt, "public static readonly nint {} = unchecked((nint){:#X});", name, value)?;
|
writeln!(
|
||||||
|
fmt,
|
||||||
|
"public static readonly nint {} = unchecked((nint){:#X});",
|
||||||
|
name, value
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(fmt, "public const nint {} = {:#X};", name, value)?;
|
writeln!(fmt, "public const nint {} = {:#X};", name, value)?;
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Write};
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{Result, anyhow};
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ enum Item<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Item<'a> {
|
impl<'a> Item<'a> {
|
||||||
#[inline]
|
|
||||||
fn write(&self, fmt: &mut Formatter<'a>, file_type: &str) -> fmt::Result {
|
fn write(&self, fmt: &mut Formatter<'a>, file_type: &str) -> fmt::Result {
|
||||||
match file_type {
|
match file_type {
|
||||||
"cs" => self.write_cs(fmt),
|
"cs" => self.write_cs(fmt),
|
||||||
@ -48,7 +47,6 @@ trait CodeWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CodeWriter for Item<'a> {
|
impl<'a> CodeWriter for Item<'a> {
|
||||||
#[inline]
|
|
||||||
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Item::Buttons(buttons) => buttons.write_cs(fmt),
|
Item::Buttons(buttons) => buttons.write_cs(fmt),
|
||||||
@ -58,7 +56,6 @@ impl<'a> CodeWriter for Item<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_hpp(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn write_hpp(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Item::Buttons(buttons) => buttons.write_hpp(fmt),
|
Item::Buttons(buttons) => buttons.write_hpp(fmt),
|
||||||
@ -68,7 +65,6 @@ impl<'a> CodeWriter for Item<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_json(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn write_json(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Item::Buttons(buttons) => buttons.write_json(fmt),
|
Item::Buttons(buttons) => buttons.write_json(fmt),
|
||||||
@ -78,7 +74,6 @@ impl<'a> CodeWriter for Item<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_rs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn write_rs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Item::Buttons(buttons) => buttons.write_rs(fmt),
|
Item::Buttons(buttons) => buttons.write_rs(fmt),
|
||||||
@ -90,7 +85,7 @@ impl<'a> CodeWriter for Item<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Output<'a> {
|
pub struct Output<'a> {
|
||||||
file_types: &'a Vec<String>,
|
file_types: &'a [String],
|
||||||
indent_size: usize,
|
indent_size: usize,
|
||||||
out_dir: &'a Path,
|
out_dir: &'a Path,
|
||||||
result: &'a AnalysisResult,
|
result: &'a AnalysisResult,
|
||||||
@ -99,7 +94,7 @@ pub struct Output<'a> {
|
|||||||
|
|
||||||
impl<'a> Output<'a> {
|
impl<'a> Output<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
file_types: &'a Vec<String>,
|
file_types: &'a [String],
|
||||||
indent_size: usize,
|
indent_size: usize,
|
||||||
out_dir: &'a Path,
|
out_dir: &'a Path,
|
||||||
result: &'a AnalysisResult,
|
result: &'a AnalysisResult,
|
||||||
@ -115,7 +110,7 @@ impl<'a> Output<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_all(&self, process: &mut IntoProcessInstanceArcBox<'_>) -> Result<()> {
|
pub fn dump_all<P: MemoryView + Process>(&self, process: &mut P) -> Result<()> {
|
||||||
let items = [
|
let items = [
|
||||||
("buttons", Item::Buttons(&self.result.buttons)),
|
("buttons", Item::Buttons(&self.result.buttons)),
|
||||||
("interfaces", Item::Interfaces(&self.result.interfaces)),
|
("interfaces", Item::Interfaces(&self.result.interfaces)),
|
||||||
@ -132,7 +127,7 @@ impl<'a> Output<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump_info(&self, process: &mut IntoProcessInstanceArcBox<'_>) -> Result<()> {
|
fn dump_info<P: MemoryView + Process>(&self, process: &mut P) -> Result<()> {
|
||||||
let file_path = self.out_dir.join("info.json");
|
let file_path = self.out_dir.join("info.json");
|
||||||
|
|
||||||
let build_number = self
|
let build_number = self
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Write};
|
|||||||
|
|
||||||
use heck::{AsPascalCase, AsSnakeCase};
|
use heck::{AsPascalCase, AsSnakeCase};
|
||||||
|
|
||||||
use super::{slugify, CodeWriter, Formatter, OffsetMap};
|
use super::{CodeWriter, Formatter, OffsetMap, slugify};
|
||||||
|
|
||||||
impl CodeWriter for OffsetMap {
|
impl CodeWriter for OffsetMap {
|
||||||
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -5,7 +5,7 @@ use heck::{AsPascalCase, AsSnakeCase};
|
|||||||
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use super::{slugify, CodeWriter, Formatter, SchemaMap};
|
use super::{CodeWriter, Formatter, SchemaMap, slugify};
|
||||||
|
|
||||||
use crate::analysis::ClassMetadata;
|
use crate::analysis::ClassMetadata;
|
||||||
|
|
||||||
@ -41,8 +41,13 @@ impl CodeWriter for SchemaMap {
|
|||||||
.members
|
.members
|
||||||
.iter()
|
.iter()
|
||||||
.map(|member| {
|
.map(|member| {
|
||||||
let hex = if member.value < 0 || member.value > i32::MAX as i64 {
|
let hex = if member.value < 0
|
||||||
format!("unchecked(({}){})", type_name, member.value)
|
|| member.value > i32::MAX as i64
|
||||||
|
{
|
||||||
|
format!(
|
||||||
|
"unchecked(({}){})",
|
||||||
|
type_name, member.value
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("{:#X}", member.value)
|
format!("{:#X}", member.value)
|
||||||
};
|
};
|
||||||
|
@ -6,8 +6,8 @@ use super::{SchemaMetadataEntryData, SchemaType};
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct SchemaClassFieldData {
|
pub struct SchemaClassFieldData {
|
||||||
pub name: Pointer64<ReprCString>, // 0x0000
|
pub name: Pointer64<ReprCString>, // 0x0000
|
||||||
pub schema_type: Pointer64<SchemaType>, // 0x0008
|
pub r#type: Pointer64<SchemaType>, // 0x0008
|
||||||
pub single_inheritance_offset: i32, // 0x0010
|
pub offset: i32, // 0x0010
|
||||||
pub metadata_count: i32, // 0x0014
|
pub metadata_count: i32, // 0x0014
|
||||||
pub metadata: Pointer64<SchemaMetadataEntryData>, // 0x0018
|
pub metadata: Pointer64<SchemaMetadataEntryData>, // 0x0018
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
use memflow::prelude::v1::*;
|
use memflow::prelude::v1::*;
|
||||||
|
|
||||||
use super::{
|
use super::*;
|
||||||
SchemaBaseClassInfoData, SchemaClassFieldData, SchemaMetadataEntryData, SchemaStaticFieldData,
|
|
||||||
SchemaSystemTypeScope, SchemaType,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub type SchemaClassBinding = SchemaClassInfoData;
|
pub type SchemaClassBinding = SchemaClassInfoData;
|
||||||
|
|
||||||
@ -28,6 +25,6 @@ pub struct SchemaClassInfoData {
|
|||||||
pad_0040: [u8; 0x8], // 0x0040
|
pad_0040: [u8; 0x8], // 0x0040
|
||||||
pub static_metadata: Pointer64<[SchemaMetadataEntryData]>, // 0x0048
|
pub static_metadata: Pointer64<[SchemaMetadataEntryData]>, // 0x0048
|
||||||
pub type_scope: Pointer64<SchemaSystemTypeScope>, // 0x0050
|
pub type_scope: Pointer64<SchemaSystemTypeScope>, // 0x0050
|
||||||
pub schema_type: Pointer64<SchemaType>, // 0x0058
|
pub r#type: Pointer64<SchemaType>, // 0x0058
|
||||||
pad_0060: [u8; 0x10], // 0x0060
|
pad_0060: [u8; 0x10], // 0x0060
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,11 @@ pub struct SchemaEnumInfoData {
|
|||||||
pub size: u8, // 0x0018
|
pub size: u8, // 0x0018
|
||||||
pub align_of: u8, // 0x0019
|
pub align_of: u8, // 0x0019
|
||||||
pad_001a: [u8; 0x2], // 0x001A
|
pad_001a: [u8; 0x2], // 0x001A
|
||||||
pub enumerator_count: u16, // 0x001C
|
pub enum_count: u16, // 0x001C
|
||||||
pub static_metadata_count: u16, // 0x001E
|
pub static_metadata_count: u16, // 0x001E
|
||||||
pub enumerators: Pointer64<[SchemaEnumeratorInfoData]>, // 0x0020
|
pub enums: Pointer64<[SchemaEnumeratorInfoData]>, // 0x0020
|
||||||
pub static_metadata: Pointer64<SchemaMetadataEntryData>, // 0x0028
|
pub static_metadata: Pointer64<SchemaMetadataEntryData>, // 0x0028
|
||||||
pub type_scope: Pointer64<SchemaSystemTypeScope>, // 0x0030
|
pub type_scope: Pointer64<SchemaSystemTypeScope>, // 0x0030
|
||||||
pub min_enumerator_value: i64, // 0x0038
|
pub min_enum_value: i64, // 0x0038
|
||||||
pub max_enumerator_value: i64, // 0x0040
|
pub max_enum_value: i64, // 0x0040
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use super::{SchemaMetadataEntryData, SchemaType};
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct SchemaStaticFieldData {
|
pub struct SchemaStaticFieldData {
|
||||||
pub name: Pointer64<ReprCString>, // 0x0000
|
pub name: Pointer64<ReprCString>, // 0x0000
|
||||||
pub type_: Pointer64<SchemaType>, // 0x0008
|
pub r#type: Pointer64<SchemaType>, // 0x0008
|
||||||
pub instance: Pointer64<()>, // 0x0010
|
pub instance: Pointer64<()>, // 0x0010
|
||||||
pub metadata_count: i32, // 0x0018
|
pub metadata_count: i32, // 0x0018
|
||||||
pad_001c: [u8; 0x4], // 0x001C
|
pad_001c: [u8; 0x4], // 0x001C
|
||||||
|
@ -13,6 +13,6 @@ pub struct SchemaSystemTypeScope {
|
|||||||
pub name: [c_char; 256], // 0x0008
|
pub name: [c_char; 256], // 0x0008
|
||||||
pub global_scope: Pointer64<SchemaSystemTypeScope>, // 0x0108
|
pub global_scope: Pointer64<SchemaSystemTypeScope>, // 0x0108
|
||||||
pad_0110: [u8; 0x3F0], // 0x0110
|
pad_0110: [u8; 0x3F0], // 0x0110
|
||||||
pub class_bindings: UtlTsHash<Pointer64<SchemaClassBinding>>, // 0x0500
|
pub class_bindings: UtlTsHash<SchemaClassBinding>, // 0x0500
|
||||||
pub enum_bindings: UtlTsHash<Pointer64<SchemaEnumBinding>>, // 0x2D90
|
pub enum_bindings: UtlTsHash<SchemaEnumBinding>, // 0x2D90
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ pub struct SchemaType {
|
|||||||
unsafe impl Pod for SchemaType {}
|
unsafe impl Pod for SchemaType {}
|
||||||
|
|
||||||
pub union SchemaTypeUnion {
|
pub union SchemaTypeUnion {
|
||||||
pub schema_type: Pointer64<SchemaType>,
|
pub r#type: Pointer64<SchemaType>,
|
||||||
pub class_binding: Pointer64<SchemaClassBinding>,
|
pub class_binding: Pointer64<SchemaClassBinding>,
|
||||||
pub enum_binding: Pointer64<SchemaEnumBinding>,
|
pub enum_binding: Pointer64<SchemaEnumBinding>,
|
||||||
pub array: SchemaArrayT,
|
pub array: SchemaArrayT,
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use anyhow::{bail, Result};
|
|
||||||
|
|
||||||
use memflow::prelude::v1::*;
|
use memflow::prelude::v1::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -10,26 +8,16 @@ pub struct UtlMemory<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Pod> UtlMemory<T> {
|
impl<T: Pod> UtlMemory<T> {
|
||||||
#[inline]
|
|
||||||
pub fn count(&self) -> i32 {
|
|
||||||
self.alloc_count
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn element(&self, process: &mut IntoProcessInstanceArcBox<'_>, idx: usize) -> Result<T> {
|
|
||||||
if idx >= self.count() as _ {
|
|
||||||
bail!("index out of bounds");
|
|
||||||
}
|
|
||||||
|
|
||||||
process
|
|
||||||
.read_ptr(self.mem.at(idx as _))
|
|
||||||
.data_part()
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_externally_allocated(&self) -> bool {
|
pub fn is_externally_allocated(&self) -> bool {
|
||||||
self.grow_size < 0
|
self.grow_size < 0
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: 'static> Pod for UtlMemory<T> {}
|
pub fn element(&self, mem: &mut impl MemoryView, index: usize) -> Result<T> {
|
||||||
|
if index >= self.alloc_count as usize {
|
||||||
|
return Err(ErrorKind::OutOfBounds.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
mem.read_ptr(self.mem.at(index as _)).data_part()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,7 +29,7 @@ pub struct UtlMemoryPoolBase {
|
|||||||
pub grow_mode: MemoryPoolGrowType, // 0x0008
|
pub grow_mode: MemoryPoolGrowType, // 0x0008
|
||||||
pub blocks_alloc: i32, // 0x000C
|
pub blocks_alloc: i32, // 0x000C
|
||||||
pub peak_alloc: i32, // 0x0010
|
pub peak_alloc: i32, // 0x0010
|
||||||
pub alignment: u16, // 0x0014
|
pub align_of: u16, // 0x0014
|
||||||
pub blob_count: u16, // 0x0016
|
pub blob_count: u16, // 0x0016
|
||||||
pub free_list_tail: Pointer64<Pointer64<FreeList>>, // 0x0018
|
pub free_list_tail: Pointer64<Pointer64<FreeList>>, // 0x0018
|
||||||
pub free_list_head: Pointer64<FreeList>, // 0x0020
|
pub free_list_head: Pointer64<FreeList>, // 0x0020
|
||||||
@ -38,10 +38,3 @@ pub struct UtlMemoryPoolBase {
|
|||||||
pub total_size: i32, // 0x0078
|
pub total_size: i32, // 0x0078
|
||||||
pad_007c: [u8; 0x4], // 0x007C
|
pad_007c: [u8; 0x4], // 0x007C
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UtlMemoryPoolBase {
|
|
||||||
#[inline]
|
|
||||||
pub fn size(&self) -> i32 {
|
|
||||||
self.total_size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use memflow::prelude::v1::*;
|
use memflow::prelude::v1::*;
|
||||||
|
|
||||||
use super::UtlMemoryPoolBase;
|
use super::UtlMemoryPoolBase;
|
||||||
|
|
||||||
use crate::mem::PointerExt;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct HashAllocatedBlob<D> {
|
pub struct HashAllocatedBlob<D> {
|
||||||
pub next: Pointer64<HashAllocatedBlob<D>>, // 0x0000
|
pub next: Pointer64<HashAllocatedBlob<D>>, // 0x0000
|
||||||
pad_0008: [u8; 0x8], // 0x0008
|
pad_0008: [u8; 0x8], // 0x0008
|
||||||
pub data: D, // 0x0010
|
pub data: Pointer64<D>, // 0x0010
|
||||||
pad_0018: [u8; 0x8], // 0x0018
|
pad_0018: [u8; 0x8], // 0x0018
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +23,7 @@ pub struct HashBucket<D, K> {
|
|||||||
pub struct HashFixedDataInternal<D, K> {
|
pub struct HashFixedDataInternal<D, K> {
|
||||||
pub ui_key: K, // 0x0000
|
pub ui_key: K, // 0x0000
|
||||||
pub next: Pointer64<HashFixedDataInternal<D, K>>, // 0x0008
|
pub next: Pointer64<HashFixedDataInternal<D, K>>, // 0x0008
|
||||||
pub data: D, // 0x0010
|
pub data: Pointer64<D>, // 0x0010
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<D: 'static, K: 'static> Pod for HashFixedDataInternal<D, K> {}
|
unsafe impl<D: 'static, K: 'static> Pod for HashFixedDataInternal<D, K> {}
|
||||||
@ -40,11 +36,7 @@ pub struct UtlTsHash<D, const C: usize = 256, K = u64> {
|
|||||||
pad_2881: [u8; 0xF], // 0x2881
|
pad_2881: [u8; 0xF], // 0x2881
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D, const C: usize, K> UtlTsHash<D, C, K>
|
impl<D: Pod, const C: usize, K: Pod> UtlTsHash<D, C, K> {
|
||||||
where
|
|
||||||
D: Pod + PointerExt,
|
|
||||||
K: Pod,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn blocks_alloc(&self) -> i32 {
|
pub fn blocks_alloc(&self) -> i32 {
|
||||||
self.entry_mem.blocks_alloc
|
self.entry_mem.blocks_alloc
|
||||||
@ -60,7 +52,7 @@ where
|
|||||||
self.entry_mem.peak_alloc
|
self.entry_mem.peak_alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn elements(&self, process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Vec<D>> {
|
pub fn elements(&self, mem: &mut impl MemoryView) -> Result<Vec<Pointer64<D>>> {
|
||||||
let blocks_alloc = self.blocks_alloc() as usize;
|
let blocks_alloc = self.blocks_alloc() as usize;
|
||||||
let peak_alloc = self.peak_count() as usize;
|
let peak_alloc = self.peak_count() as usize;
|
||||||
|
|
||||||
@ -71,7 +63,7 @@ where
|
|||||||
let mut cur_element = bucket.first_uncommitted;
|
let mut cur_element = bucket.first_uncommitted;
|
||||||
|
|
||||||
while !cur_element.is_null() {
|
while !cur_element.is_null() {
|
||||||
let element = process.read_ptr(cur_element).data_part()?;
|
let element = mem.read_ptr(cur_element).data_part()?;
|
||||||
|
|
||||||
if !element.data.is_null() {
|
if !element.data.is_null() {
|
||||||
allocated_list.push(element.data);
|
allocated_list.push(element.data);
|
||||||
@ -89,7 +81,7 @@ where
|
|||||||
Pointer64::<HashAllocatedBlob<D>>::from(self.entry_mem.free_list_head.address());
|
Pointer64::<HashAllocatedBlob<D>>::from(self.entry_mem.free_list_head.address());
|
||||||
|
|
||||||
while !cur_blob.is_null() {
|
while !cur_blob.is_null() {
|
||||||
let blob = process.read_ptr(cur_blob).data_part()?;
|
let blob = mem.read_ptr(cur_blob).data_part()?;
|
||||||
|
|
||||||
if !blob.data.is_null() {
|
if !blob.data.is_null() {
|
||||||
unallocated_list.push(blob.data);
|
unallocated_list.push(blob.data);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use anyhow::{bail, Result};
|
|
||||||
|
|
||||||
use memflow::prelude::v1::*;
|
use memflow::prelude::v1::*;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -10,20 +8,12 @@ pub struct UtlVector<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Pod> UtlVector<T> {
|
impl<T: Pod> UtlVector<T> {
|
||||||
#[inline]
|
pub fn element(&self, mem: &mut impl MemoryView, index: usize) -> Result<T> {
|
||||||
pub fn count(&self) -> i32 {
|
if index >= self.size as usize {
|
||||||
self.size
|
return Err(ErrorKind::OutOfBounds.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn element(&self, process: &mut IntoProcessInstanceArcBox<'_>, idx: usize) -> Result<T> {
|
mem.read_ptr(self.mem.at(index as _)).data_part()
|
||||||
if idx >= self.count() as usize {
|
|
||||||
bail!("index out of bounds");
|
|
||||||
}
|
|
||||||
|
|
||||||
process
|
|
||||||
.read_ptr(self.mem.at(idx as _))
|
|
||||||
.data_part()
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user