mirror of
https://github.com/a2x/cs2-dumper.git
synced 2025-10-08 05:10:02 +08:00
0.1.2
* Updated for memflow 0.2.2 * Replaced periods with underscores in generated file names for easier inclusion * Program execution now continues if analysis fails at any point * Removed custom error type in favor of anyhow * Added logging to cs2-dumper.log * Now compilable on Linux
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use log::debug;
|
||||
|
||||
use memflow::prelude::v1::*;
|
||||
@@ -5,20 +9,16 @@ use memflow::prelude::v1::*;
|
||||
use pelite::pattern;
|
||||
use pelite::pe64::{Pe, PeView};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::source2::KeyButton;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Button {
|
||||
pub name: String,
|
||||
pub value: u32,
|
||||
}
|
||||
pub type ButtonMap = BTreeMap<String, imem>;
|
||||
|
||||
pub fn buttons(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Vec<Button>> {
|
||||
pub fn buttons(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<ButtonMap> {
|
||||
let module = process.module_by_name("client.dll")?;
|
||||
let buf = process.read_raw(module.base, module.size as _)?;
|
||||
|
||||
let buf = process
|
||||
.read_raw(module.base, module.size as _)
|
||||
.data_part()?;
|
||||
|
||||
let view = PeView::from_bytes(&buf)?;
|
||||
|
||||
@@ -28,7 +28,7 @@ pub fn buttons(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Vec<Button
|
||||
.scanner()
|
||||
.finds_code(pattern!("488b15${'} 4885d2 74? 0f1f40"), &mut save)
|
||||
{
|
||||
return Err(Error::Other("unable to find button list pattern"));
|
||||
bail!("outdated button list pattern");
|
||||
}
|
||||
|
||||
read_buttons(process, &module, module.base + save[1])
|
||||
@@ -38,32 +38,28 @@ fn read_buttons(
|
||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
||||
module: &ModuleInfo,
|
||||
list_addr: Address,
|
||||
) -> Result<Vec<Button>> {
|
||||
let mut buttons = Vec::new();
|
||||
) -> Result<ButtonMap> {
|
||||
let mut map = ButtonMap::new();
|
||||
|
||||
let mut cur_button = Pointer64::<KeyButton>::from(process.read_addr64(list_addr)?);
|
||||
let mut cur_button = Pointer64::<KeyButton>::from(process.read_addr64(list_addr).data_part()?);
|
||||
|
||||
while !cur_button.is_null() {
|
||||
let button = cur_button.read(process)?;
|
||||
let name = button.name.read_string(process)?.to_string();
|
||||
|
||||
let value =
|
||||
((cur_button.address() - module.base) + offset_of!(KeyButton.state) as i64) as u32;
|
||||
let button = process.read_ptr(cur_button).data_part()?;
|
||||
let name = process.read_utf8(button.name.address(), 32).data_part()?;
|
||||
let rva = (cur_button.address() - module.base) + offset_of!(KeyButton.state) as imem;
|
||||
|
||||
debug!(
|
||||
"found button: {} @ {:#X} ({} + {:#X})",
|
||||
"found button: {} at {:#X} ({} + {:#X})",
|
||||
name,
|
||||
value as u64 + module.base.to_umem(),
|
||||
cur_button.to_umem() + offset_of!(KeyButton.state) as umem,
|
||||
module.name,
|
||||
value
|
||||
rva
|
||||
);
|
||||
|
||||
buttons.push(Button { name, value });
|
||||
map.insert(name, rva);
|
||||
|
||||
cur_button = button.next;
|
||||
}
|
||||
|
||||
buttons.sort_unstable_by(|a, b| a.name.cmp(&b.name));
|
||||
|
||||
Ok(buttons)
|
||||
Ok(map)
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use log::debug;
|
||||
|
||||
use memflow::prelude::v1::*;
|
||||
@@ -7,25 +9,20 @@ use memflow::prelude::v1::*;
|
||||
use pelite::pe64::exports::Export;
|
||||
use pelite::pe64::{Pe, PeView};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::mem::read_addr64_rip;
|
||||
use crate::source2::InterfaceReg;
|
||||
|
||||
pub type InterfaceMap = BTreeMap<String, Vec<Interface>>;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Interface {
|
||||
pub name: String,
|
||||
pub value: u32,
|
||||
}
|
||||
pub type InterfaceMap = BTreeMap<String, BTreeMap<String, imem>>;
|
||||
|
||||
pub fn interfaces(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<InterfaceMap> {
|
||||
process
|
||||
.module_list()?
|
||||
.iter()
|
||||
.filter_map(|module| {
|
||||
let buf = process.read_raw(module.base, module.size as _).ok()?;
|
||||
let buf = process
|
||||
.read_raw(module.base, module.size as _)
|
||||
.data_part()
|
||||
.ok()?;
|
||||
|
||||
let view = PeView::from_bytes(&buf).ok()?;
|
||||
|
||||
@@ -38,8 +35,7 @@ pub fn interfaces(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Interfa
|
||||
.ok()?;
|
||||
|
||||
if let Export::Symbol(symbol) = ci_export {
|
||||
let list_addr = process
|
||||
.read_addr64_rip(module.base + symbol)
|
||||
let list_addr = read_addr64_rip(process, module.base + symbol)
|
||||
.data_part()
|
||||
.ok()?;
|
||||
|
||||
@@ -58,32 +54,29 @@ fn read_interfaces(
|
||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
||||
module: &ModuleInfo,
|
||||
list_addr: Address,
|
||||
) -> Result<Vec<Interface>> {
|
||||
let mut ifaces = Vec::new();
|
||||
) -> Result<BTreeMap<String, imem>> {
|
||||
let mut ifaces = BTreeMap::new();
|
||||
|
||||
let mut cur_reg = Pointer64::<InterfaceReg>::from(process.read_addr64(list_addr)?);
|
||||
let mut cur_reg = Pointer64::<InterfaceReg>::from(process.read_addr64(list_addr).data_part()?);
|
||||
|
||||
while !cur_reg.is_null() {
|
||||
let reg = cur_reg.read(process)?;
|
||||
let name = reg.name.read_string(process)?.to_string();
|
||||
let instance = process.read_addr64_rip(reg.create_fn.address())?;
|
||||
|
||||
let value = (instance - module.base) as u32;
|
||||
let reg = process.read_ptr(cur_reg).data_part()?;
|
||||
let name = process.read_utf8(reg.name.address(), 4096).data_part()?;
|
||||
let instance = read_addr64_rip(process, reg.create_fn.address())?;
|
||||
let value = instance - module.base;
|
||||
|
||||
debug!(
|
||||
"found interface: {} @ {:#X} ({} + {:#X})",
|
||||
"found interface: {} at {:#X} ({} + {:#X})",
|
||||
name,
|
||||
value as u64 + module.base.to_umem(),
|
||||
module.name,
|
||||
value
|
||||
);
|
||||
|
||||
ifaces.push(Interface { name, value });
|
||||
ifaces.insert(name, value);
|
||||
|
||||
cur_reg = reg.next;
|
||||
}
|
||||
|
||||
ifaces.sort_unstable_by(|a, b| a.name.cmp(&b.name));
|
||||
|
||||
Ok(ifaces)
|
||||
}
|
||||
|
@@ -3,27 +3,69 @@ pub use interfaces::*;
|
||||
pub use offsets::*;
|
||||
pub use schemas::*;
|
||||
|
||||
use memflow::prelude::v1::*;
|
||||
use std::any::type_name;
|
||||
|
||||
use crate::error::Result;
|
||||
use anyhow::Result;
|
||||
|
||||
use log::{error, info};
|
||||
|
||||
use memflow::prelude::v1::*;
|
||||
|
||||
mod buttons;
|
||||
mod interfaces;
|
||||
mod offsets;
|
||||
mod schemas;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AnalysisResult {
|
||||
pub buttons: Vec<Button>,
|
||||
pub buttons: ButtonMap,
|
||||
pub interfaces: InterfaceMap,
|
||||
pub offsets: OffsetMap,
|
||||
pub schemas: SchemaMap,
|
||||
}
|
||||
|
||||
pub fn analyze_all(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<AnalysisResult> {
|
||||
let buttons = buttons(process)?;
|
||||
let interfaces = interfaces(process)?;
|
||||
let offsets = offsets(process)?;
|
||||
let schemas = schemas(process)?;
|
||||
let buttons = analyze(process, buttons);
|
||||
|
||||
info!("found {} buttons", buttons.len());
|
||||
|
||||
let interfaces = analyze(process, interfaces);
|
||||
|
||||
info!(
|
||||
"found {} interfaces across {} modules",
|
||||
interfaces
|
||||
.iter()
|
||||
.map(|(_, ifaces)| ifaces.len())
|
||||
.sum::<usize>(),
|
||||
interfaces.len()
|
||||
);
|
||||
|
||||
let offsets = analyze(process, offsets);
|
||||
|
||||
info!(
|
||||
"found {} offsets across {} modules",
|
||||
offsets
|
||||
.iter()
|
||||
.map(|(_, offsets)| offsets.len())
|
||||
.sum::<usize>(),
|
||||
offsets.len()
|
||||
);
|
||||
|
||||
let schemas = analyze(process, schemas);
|
||||
|
||||
let (class_count, enum_count) =
|
||||
schemas
|
||||
.values()
|
||||
.fold((0, 0), |(classes, enums), (class_vec, enum_vec)| {
|
||||
(classes + class_vec.len(), enums + enum_vec.len())
|
||||
});
|
||||
|
||||
info!(
|
||||
"found {} classes and {} enums across {} modules",
|
||||
class_count,
|
||||
enum_count,
|
||||
schemas.len()
|
||||
);
|
||||
|
||||
Ok(AnalysisResult {
|
||||
buttons,
|
||||
@@ -32,3 +74,21 @@ pub fn analyze_all(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Analys
|
||||
schemas,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn analyze<F, T>(process: &mut IntoProcessInstanceArcBox<'_>, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut IntoProcessInstanceArcBox<'_>) -> Result<T>,
|
||||
T: Default,
|
||||
{
|
||||
let name = type_name::<F>();
|
||||
|
||||
match f(process) {
|
||||
Ok(result) => result,
|
||||
Err(err) => {
|
||||
error!("failed to read {}: {}", name, err);
|
||||
|
||||
T::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,18 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use log::{debug, error};
|
||||
|
||||
use memflow::prelude::v1::*;
|
||||
|
||||
use pelite::pattern;
|
||||
use pelite::pattern::{save_len, Atom};
|
||||
use pelite::pe64::{Pe, PeView};
|
||||
use pelite::pe64::{Pe, PeView, Rva};
|
||||
|
||||
use phf::{phf_map, Map};
|
||||
|
||||
use crate::error::Result;
|
||||
|
||||
pub type OffsetMap = BTreeMap<String, BTreeMap<String, u32>>;
|
||||
pub type OffsetMap = BTreeMap<String, BTreeMap<String, Rva>>;
|
||||
|
||||
macro_rules! pattern_map {
|
||||
($($module:ident => {
|
||||
@@ -26,20 +26,20 @@ macro_rules! pattern_map {
|
||||
&'static str,
|
||||
(
|
||||
&'static [Atom],
|
||||
Option<fn(&PeView, &mut BTreeMap<String, u32>, u32)>,
|
||||
Option<fn(&PeView, &mut BTreeMap<String, Rva>, Rva)>,
|
||||
),
|
||||
> = phf_map! {
|
||||
$($name => ($pattern, $($callback)?)),+
|
||||
};
|
||||
|
||||
pub fn offsets(view: PeView<'_>) -> BTreeMap<String, u32> {
|
||||
pub fn offsets(view: PeView<'_>) -> BTreeMap<String, Rva> {
|
||||
let mut map = BTreeMap::new();
|
||||
|
||||
for (&name, (pat, callback)) in &PATTERNS {
|
||||
let mut save = vec![0; save_len(pat)];
|
||||
|
||||
if !view.scanner().finds_code(pat, &mut save) {
|
||||
error!("unable to find pattern: {}", name);
|
||||
error!("outdated pattern: {}", name);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ macro_rules! pattern_map {
|
||||
|
||||
for (name, value) in &map {
|
||||
debug!(
|
||||
"found offset: {} @ {:#X} ({}.dll + {:#X})",
|
||||
"found offset: {} at {:#X} ({}.dll + {:#X})",
|
||||
name,
|
||||
*value as u64 + view.optional_header().ImageBase,
|
||||
stringify!($module),
|
||||
@@ -130,8 +130,11 @@ pattern_map! {
|
||||
pub fn offsets(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<OffsetMap> {
|
||||
let mut map = BTreeMap::new();
|
||||
|
||||
let modules: [(&str, fn(PeView) -> BTreeMap<String, u32>); 5] = [
|
||||
("client.dll", client::offsets),
|
||||
let modules = [
|
||||
(
|
||||
"client.dll",
|
||||
client::offsets as fn(PeView) -> BTreeMap<String, u32>,
|
||||
),
|
||||
("engine2.dll", engine2::offsets),
|
||||
("inputsystem.dll", input_system::offsets),
|
||||
("matchmaking.dll", matchmaking::offsets),
|
||||
@@ -140,7 +143,10 @@ pub fn offsets(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<OffsetMap>
|
||||
|
||||
for (module_name, offsets) in &modules {
|
||||
let module = process.module_by_name(module_name)?;
|
||||
let buf = process.read_raw(module.base, module.size as _)?;
|
||||
|
||||
let buf = process
|
||||
.read_raw(module.base, module.size as _)
|
||||
.data_part()?;
|
||||
|
||||
let view = PeView::from_bytes(&buf)?;
|
||||
|
||||
@@ -218,7 +224,7 @@ mod tests {
|
||||
.read_addr64((global_vars + 0x1B8).into())
|
||||
.data_part()?;
|
||||
|
||||
process.read_char_string(addr).data_part()?
|
||||
process.read_utf8(addr, 4096).data_part()?
|
||||
};
|
||||
|
||||
println!("current map name: {}", cur_map_name);
|
||||
@@ -244,7 +250,7 @@ mod tests {
|
||||
.data_part()?;
|
||||
|
||||
let player_name = process
|
||||
.read_char_string((local_player_controller + player_name_offset).into())
|
||||
.read_utf8((local_player_controller + player_name_offset).into(), 4096)
|
||||
.data_part()?;
|
||||
|
||||
println!("local player name: {}", player_name);
|
||||
|
@@ -1,6 +1,8 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::CStr;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use log::debug;
|
||||
|
||||
use memflow::prelude::v1::*;
|
||||
@@ -10,7 +12,6 @@ use pelite::pe64::{Pe, PeView};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::source2::*;
|
||||
|
||||
pub type SchemaMap = BTreeMap<String, (Vec<Class>, Vec<Enum>)>;
|
||||
@@ -80,30 +81,34 @@ fn read_class_binding(
|
||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
||||
binding_ptr: Pointer64<SchemaClassBinding>,
|
||||
) -> Result<Class> {
|
||||
let binding = binding_ptr.read(process)?;
|
||||
let binding = process.read_ptr(binding_ptr).data_part()?;
|
||||
|
||||
let module_name = binding
|
||||
.module_name
|
||||
.read_string(process)
|
||||
let module_name = process
|
||||
.read_utf8(binding.module_name.address(), 4096)
|
||||
.data_part()
|
||||
.map(|s| format!("{}.dll", s))?;
|
||||
|
||||
let name = binding.name.read_string(process)?.to_string();
|
||||
let name = process
|
||||
.read_utf8(binding.name.address(), 4096)
|
||||
.data_part()?;
|
||||
|
||||
if name.is_empty() {
|
||||
return Err(Error::Other("empty class name"));
|
||||
bail!("empty class name");
|
||||
}
|
||||
|
||||
let parent = binding.base_classes.non_null().and_then(|ptr| {
|
||||
let base_class = ptr.read(process).ok()?;
|
||||
let parent_class = base_class.prev.read(process).ok()?;
|
||||
let base_class = process.read_ptr(ptr).data_part().ok()?;
|
||||
let parent_class = process.read_ptr(base_class.prev).data_part().ok()?;
|
||||
|
||||
let module_name = parent_class
|
||||
.module_name
|
||||
.read_string(process)
|
||||
.ok()?
|
||||
.to_string();
|
||||
let module_name = process
|
||||
.read_utf8(parent_class.module_name.address(), 4096)
|
||||
.data_part()
|
||||
.ok()?;
|
||||
|
||||
let name = parent_class.name.read_string(process).ok()?.to_string();
|
||||
let name = process
|
||||
.read_utf8(parent_class.name.address(), 4096)
|
||||
.data_part()
|
||||
.ok()?;
|
||||
|
||||
Some(Box::new(Class {
|
||||
name,
|
||||
@@ -118,11 +123,11 @@ fn read_class_binding(
|
||||
let metadata = read_class_binding_metadata(process, &binding)?;
|
||||
|
||||
debug!(
|
||||
"found class: {} @ {:#X} (module name: {}) (parent name: {:?}) (metadata count: {}) (fields count: {})",
|
||||
"found class: {} at {:#X} (module name: {}) (parent name: {:?}) (metadata count: {}) (field count: {})",
|
||||
name,
|
||||
binding_ptr.to_umem(),
|
||||
module_name,
|
||||
parent.as_ref().map(|parent| parent.name.clone()),
|
||||
parent.as_ref().map(|p| p.name.clone()),
|
||||
metadata.len(),
|
||||
fields.len(),
|
||||
);
|
||||
@@ -144,18 +149,21 @@ fn read_class_binding_fields(
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
(0..binding.fields_count).try_fold(Vec::new(), |mut acc, i| {
|
||||
let field = binding.fields.at(i as _).read(process)?;
|
||||
(0..binding.field_count).try_fold(Vec::new(), |mut acc, i| {
|
||||
let field = process.read_ptr(binding.fields.at(i as _)).data_part()?;
|
||||
|
||||
if field.schema_type.is_null() {
|
||||
return Ok(acc);
|
||||
}
|
||||
|
||||
let name = field.name.read_string(process)?.to_string();
|
||||
let schema_type = field.schema_type.read(process)?;
|
||||
let name = process.read_utf8(field.name.address(), 4096).data_part()?;
|
||||
let schema_type = process.read_ptr(field.schema_type).data_part()?;
|
||||
|
||||
// TODO: Parse this properly.
|
||||
let type_name = schema_type.name.read_string(process)?.replace(" ", "");
|
||||
let type_name = process
|
||||
.read_utf8(schema_type.name.address(), 4096)
|
||||
.data_part()?
|
||||
.replace(" ", "");
|
||||
|
||||
acc.push(ClassField {
|
||||
name,
|
||||
@@ -176,30 +184,39 @@ fn read_class_binding_metadata(
|
||||
}
|
||||
|
||||
(0..binding.static_metadata_count).try_fold(Vec::new(), |mut acc, i| {
|
||||
let metadata = binding.static_metadata.at(i as _).read(process)?;
|
||||
let metadata = process
|
||||
.read_ptr(binding.static_metadata.at(i as _))
|
||||
.data_part()?;
|
||||
|
||||
if metadata.network_value.is_null() {
|
||||
return Ok(acc);
|
||||
}
|
||||
|
||||
let name = metadata.name.read_string(process)?.to_string();
|
||||
let network_value = metadata.network_value.read(process)?;
|
||||
let name = process
|
||||
.read_utf8(metadata.name.address(), 4096)
|
||||
.data_part()?;
|
||||
|
||||
let network_value = process.read_ptr(metadata.network_value).data_part()?;
|
||||
|
||||
let metadata = match name.as_str() {
|
||||
"MNetworkChangeCallback" => unsafe {
|
||||
let name = network_value
|
||||
.value
|
||||
.name_ptr
|
||||
.read_string(process)?
|
||||
.to_string();
|
||||
let name = process
|
||||
.read_utf8(network_value.value.name_ptr.address(), 4096)
|
||||
.data_part()?;
|
||||
|
||||
ClassMetadata::NetworkChangeCallback { name }
|
||||
},
|
||||
"MNetworkVarNames" => unsafe {
|
||||
let var_value = network_value.value.var_value;
|
||||
|
||||
let name = var_value.name.read_string(process)?.to_string();
|
||||
let type_name = var_value.type_name.read_string(process)?.replace(" ", "");
|
||||
let name = process
|
||||
.read_utf8(var_value.name.address(), 4096)
|
||||
.data_part()?;
|
||||
|
||||
let type_name = process
|
||||
.read_utf8(var_value.type_name.address(), 4096)
|
||||
.data_part()?
|
||||
.replace(" ", "");
|
||||
|
||||
ClassMetadata::NetworkVarNames { name, type_name }
|
||||
},
|
||||
@@ -216,17 +233,20 @@ fn read_enum_binding(
|
||||
process: &mut IntoProcessInstanceArcBox<'_>,
|
||||
binding_ptr: Pointer64<SchemaEnumBinding>,
|
||||
) -> Result<Enum> {
|
||||
let binding = binding_ptr.read(process)?;
|
||||
let name = binding.name.read_string(process)?.to_string();
|
||||
let binding = process.read_ptr(binding_ptr).data_part()?;
|
||||
|
||||
let name = process
|
||||
.read_utf8(binding.name.address(), 4096)
|
||||
.data_part()?;
|
||||
|
||||
if name.is_empty() {
|
||||
return Err(Error::Other("empty enum name"));
|
||||
bail!("empty enum name");
|
||||
}
|
||||
|
||||
let members = read_enum_binding_members(process, &binding)?;
|
||||
|
||||
debug!(
|
||||
"found enum: {} @ {:#X} (alignment: {}) (members count: {})",
|
||||
"found enum: {} at {:#X} (alignment: {}) (member count: {})",
|
||||
name,
|
||||
binding_ptr.to_umem(),
|
||||
binding.align_of,
|
||||
@@ -236,7 +256,7 @@ fn read_enum_binding(
|
||||
Ok(Enum {
|
||||
name,
|
||||
alignment: binding.align_of,
|
||||
size: binding.enumerators_count,
|
||||
size: binding.enumerator_count,
|
||||
members,
|
||||
})
|
||||
}
|
||||
@@ -249,9 +269,14 @@ fn read_enum_binding_members(
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
(0..binding.enumerators_count).try_fold(Vec::new(), |mut acc, i| {
|
||||
let enumerator = binding.enumerators.at(i as _).read(process)?;
|
||||
let name = enumerator.name.read_string(process)?.to_string();
|
||||
(0..binding.enumerator_count).try_fold(Vec::new(), |mut acc, i| {
|
||||
let enumerator = process
|
||||
.read_ptr(binding.enumerators.at(i as _))
|
||||
.data_part()?;
|
||||
|
||||
let name = process
|
||||
.read_utf8(enumerator.name.address(), 4096)
|
||||
.data_part()?;
|
||||
|
||||
acc.push(EnumMember {
|
||||
name,
|
||||
@@ -264,7 +289,10 @@ fn read_enum_binding_members(
|
||||
|
||||
fn read_schema_system(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<SchemaSystem> {
|
||||
let module = process.module_by_name("schemasystem.dll")?;
|
||||
let buf = process.read_raw(module.base, module.size as _)?;
|
||||
|
||||
let buf = process
|
||||
.read_raw(module.base, module.size as _)
|
||||
.data_part()?;
|
||||
|
||||
let view = PeView::from_bytes(&buf)?;
|
||||
|
||||
@@ -274,13 +302,13 @@ fn read_schema_system(process: &mut IntoProcessInstanceArcBox<'_>) -> Result<Sch
|
||||
.scanner()
|
||||
.finds_code(pattern!("4c8d35${'} 0f2845"), &mut save)
|
||||
{
|
||||
return Err(Error::Other("unable to find schema system pattern"));
|
||||
bail!("outdated schema system pattern");
|
||||
}
|
||||
|
||||
let schema_system: SchemaSystem = process.read(module.base + save[1])?;
|
||||
let schema_system: SchemaSystem = process.read(module.base + save[1]).data_part()?;
|
||||
|
||||
if schema_system.num_registrations == 0 {
|
||||
return Err(Error::Other("no schema system registrations found"));
|
||||
bail!("no schema system registrations found");
|
||||
}
|
||||
|
||||
Ok(schema_system)
|
||||
@@ -294,7 +322,7 @@ fn read_type_scopes(
|
||||
|
||||
(0..type_scopes.size).try_fold(Vec::new(), |mut acc, i| {
|
||||
let type_scope_ptr = type_scopes.element(process, i as _)?;
|
||||
let type_scope = type_scope_ptr.read(process)?;
|
||||
let type_scope = process.read_ptr(type_scope_ptr).data_part()?;
|
||||
|
||||
let module_name = unsafe { CStr::from_ptr(type_scope.name.as_ptr()) }
|
||||
.to_string_lossy()
|
||||
@@ -319,7 +347,7 @@ fn read_type_scopes(
|
||||
}
|
||||
|
||||
debug!(
|
||||
"found type scope: {} @ {:#X} (classes count: {}) (enums count: {})",
|
||||
"found type scope: {} at {:#X} (class count: {}) (enum count: {})",
|
||||
module_name,
|
||||
type_scope_ptr.to_umem(),
|
||||
classes.len(),
|
||||
|
Reference in New Issue
Block a user