* 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:
a2x
2024-07-30 02:06:35 +10:00
parent 8897183075
commit 7933103b03
98 changed files with 8413 additions and 8332 deletions

View File

@@ -1,20 +1,16 @@
use std::collections::BTreeMap;
use std::fmt::{self, Write};
use super::{Button, CodeWriter, Formatter};
use super::{ButtonMap, CodeWriter, Formatter};
impl CodeWriter for Vec<Button> {
impl CodeWriter for ButtonMap {
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
fmt.block("namespace CS2Dumper", false, |fmt| {
writeln!(fmt, "// Module: client.dll")?;
fmt.block("public static class Buttons", false, |fmt| {
for button in self {
writeln!(
fmt,
"public const nint {} = {:#X};",
button.name, button.value
)?;
for (name, value) in self {
writeln!(fmt, "public const nint {} = {:#X};", name, value)?;
}
Ok(())
@@ -30,12 +26,8 @@ impl CodeWriter for Vec<Button> {
writeln!(fmt, "// Module: client.dll")?;
fmt.block("namespace buttons", false, |fmt| {
for button in self {
writeln!(
fmt,
"constexpr std::ptrdiff_t {} = {:#X};",
button.name, button.value
)?;
for (name, value) in self {
writeln!(fmt, "constexpr std::ptrdiff_t {} = {:#X};", name, value)?;
}
Ok(())
@@ -45,15 +37,12 @@ impl CodeWriter for Vec<Button> {
fn write_json(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
let content = {
let buttons: BTreeMap<_, _> = self
.iter()
.map(|button| (button.name.as_str(), button.value))
.collect();
let buttons: BTreeMap<_, _> = self.iter().map(|(name, value)| (name, value)).collect();
BTreeMap::from_iter([("client.dll", buttons)])
};
fmt.write_str(&serde_json::to_string_pretty(&content).expect("unable to serialize json"))
fmt.write_str(&serde_json::to_string_pretty(&content).unwrap())
}
fn write_rs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
@@ -63,14 +52,14 @@ impl CodeWriter for Vec<Button> {
writeln!(fmt, "// Module: client.dll")?;
fmt.block("pub mod buttons", false, |fmt| {
for button in self {
let mut name = button.name.clone();
for (name, value) in self {
let mut name = name.clone();
if name == "use" {
name = format!("r#{}", name);
}
writeln!(fmt, "pub const {}: usize = {:#X};", name, button.value)?;
writeln!(fmt, "pub const {}: usize = {:#X};", name, value)?;
}
Ok(())

View File

@@ -15,12 +15,8 @@ impl CodeWriter for InterfaceMap {
&format!("public static class {}", AsPascalCase(slugify(module_name))),
false,
|fmt| {
for iface in ifaces {
writeln!(
fmt,
"public const nint {} = {:#X};",
iface.name, iface.value
)?;
for (name, value) in ifaces {
writeln!(fmt, "public const nint {} = {:#X};", name, value)?;
}
Ok(())
@@ -45,12 +41,8 @@ impl CodeWriter for InterfaceMap {
&format!("namespace {}", AsSnakeCase(slugify(module_name))),
false,
|fmt| {
for iface in ifaces {
writeln!(
fmt,
"constexpr std::ptrdiff_t {} = {:#X};",
iface.name, iface.value
)?;
for (name, value) in ifaces {
writeln!(fmt, "constexpr std::ptrdiff_t {} = {:#X};", name, value)?;
}
Ok(())
@@ -67,16 +59,14 @@ impl CodeWriter for InterfaceMap {
let content: BTreeMap<_, _> = self
.iter()
.map(|(module_name, ifaces)| {
let ifaces: BTreeMap<_, _> = ifaces
.iter()
.map(|iface| (&iface.name, iface.value))
.collect();
let ifaces: BTreeMap<_, _> =
ifaces.iter().map(|(name, value)| (name, value)).collect();
(module_name, ifaces)
})
.collect();
fmt.write_str(&serde_json::to_string_pretty(&content).expect("unable to serialize json"))
fmt.write_str(&serde_json::to_string_pretty(&content).unwrap())
}
fn write_rs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
@@ -91,12 +81,8 @@ impl CodeWriter for InterfaceMap {
&format!("pub mod {}", AsSnakeCase(slugify(module_name))),
false,
|fmt| {
for iface in ifaces {
writeln!(
fmt,
"pub const {}: usize = {:#X};",
iface.name, iface.value
)?;
for (name, value) in ifaces {
writeln!(fmt, "pub const {}: usize = {:#X};", name, value)?;
}
Ok(())

View File

@@ -2,6 +2,8 @@ use std::fmt::{self, Write};
use std::fs;
use std::path::Path;
use anyhow::{anyhow, Result};
use chrono::{DateTime, Utc};
use memflow::prelude::v1::*;
@@ -11,7 +13,6 @@ use serde_json::json;
use formatter::Formatter;
use crate::analysis::*;
use crate::error::{Error, Result};
mod buttons;
mod formatter;
@@ -20,13 +21,14 @@ mod offsets;
mod schemas;
enum Item<'a> {
Buttons(&'a Vec<Button>),
Buttons(&'a ButtonMap),
Interfaces(&'a InterfaceMap),
Offsets(&'a OffsetMap),
Schemas(&'a SchemaMap),
}
impl<'a> Item<'a> {
#[inline]
fn write(&self, fmt: &mut Formatter<'a>, file_type: &str) -> fmt::Result {
match file_type {
"cs" => self.write_cs(fmt),
@@ -46,6 +48,7 @@ trait CodeWriter {
}
impl<'a> CodeWriter for Item<'a> {
#[inline]
fn write_cs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match self {
Item::Buttons(buttons) => buttons.write_cs(fmt),
@@ -55,6 +58,7 @@ impl<'a> CodeWriter for Item<'a> {
}
}
#[inline]
fn write_hpp(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match self {
Item::Buttons(buttons) => buttons.write_hpp(fmt),
@@ -64,6 +68,7 @@ impl<'a> CodeWriter for Item<'a> {
}
}
#[inline]
fn write_json(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match self {
Item::Buttons(buttons) => buttons.write_json(fmt),
@@ -73,6 +78,7 @@ impl<'a> CodeWriter for Item<'a> {
}
}
#[inline]
fn write_rs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match self {
Item::Buttons(buttons) => buttons.write_rs(fmt),
@@ -137,9 +143,9 @@ impl<'a> Output<'a> {
let module = process.module_by_name(module_name).ok()?;
let offset = offsets.iter().find(|(name, _)| *name == "dwBuildNumber")?.1;
process.read::<u32>(module.base + offset).ok()
process.read::<u32>(module.base + offset).data_part().ok()
})
.ok_or(Error::Other("unable to read build number"))?;
.ok_or(anyhow!("failed to read build number"))?;
let content = serde_json::to_string_pretty(&json!({
"timestamp": self.timestamp.to_rfc3339(),
@@ -174,7 +180,7 @@ impl<'a> Output<'a> {
for (module_name, (classes, enums)) in &self.result.schemas {
let map = SchemaMap::from([(module_name.clone(), (classes.clone(), enums.clone()))]);
self.dump_item(module_name, &Item::Schemas(&map))?;
self.dump_item(&slugify(&module_name), &Item::Schemas(&map))?;
}
Ok(())
@@ -188,6 +194,7 @@ impl<'a> Output<'a> {
}
}
#[inline]
fn slugify(input: &str) -> String {
input.replace(|c: char| !c.is_alphanumeric(), "_")
}

View File

@@ -55,7 +55,7 @@ impl CodeWriter for OffsetMap {
}
fn write_json(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
fmt.write_str(&serde_json::to_string_pretty(self).expect("unable to serialize json"))
fmt.write_str(&serde_json::to_string_pretty(self).unwrap())
}
fn write_rs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {

View File

@@ -31,7 +31,7 @@ impl CodeWriter for SchemaMap {
};
writeln!(fmt, "// Alignment: {}", enum_.alignment)?;
writeln!(fmt, "// Members count: {}", enum_.size)?;
writeln!(fmt, "// Member count: {}", enum_.size)?;
fmt.block(
&format!("public enum {} : {}", slugify(&enum_.name), type_name),
@@ -59,7 +59,7 @@ impl CodeWriter for SchemaMap {
.unwrap_or_else(|| String::from("None"));
writeln!(fmt, "// Parent: {}", parent_name)?;
writeln!(fmt, "// Fields count: {}", class.fields.len())?;
writeln!(fmt, "// Field count: {}", class.fields.len())?;
write_metadata(fmt, &class.metadata)?;
@@ -114,7 +114,7 @@ impl CodeWriter for SchemaMap {
};
writeln!(fmt, "// Alignment: {}", enum_.alignment)?;
writeln!(fmt, "// Members count: {}", enum_.size)?;
writeln!(fmt, "// Member count: {}", enum_.size)?;
fmt.block(
&format!("enum class {} : {}", slugify(&enum_.name), type_name),
@@ -142,7 +142,7 @@ impl CodeWriter for SchemaMap {
.unwrap_or_else(|| String::from("None"));
writeln!(fmt, "// Parent: {}", parent_name)?;
writeln!(fmt, "// Fields count: {}", class.fields.len())?;
writeln!(fmt, "// Field count: {}", class.fields.len())?;
write_metadata(fmt, &class.metadata)?;
@@ -255,7 +255,7 @@ impl CodeWriter for SchemaMap {
})
.collect();
fmt.write_str(&serde_json::to_string_pretty(&content).expect("unable to serialize json"))
fmt.write_str(&serde_json::to_string_pretty(&content).unwrap())
}
fn write_rs(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
@@ -285,7 +285,7 @@ impl CodeWriter for SchemaMap {
};
writeln!(fmt, "// Alignment: {}", enum_.alignment)?;
writeln!(fmt, "// Members count: {}", enum_.size)?;
writeln!(fmt, "// Member count: {}", enum_.size)?;
fmt.block(
&format!(
@@ -330,7 +330,7 @@ impl CodeWriter for SchemaMap {
.unwrap_or_else(|| String::from("None"));
writeln!(fmt, "// Parent: {}", parent_name)?;
writeln!(fmt, "// Fields count: {}", class.fields.len())?;
writeln!(fmt, "// Field count: {}", class.fields.len())?;
write_metadata(fmt, &class.metadata)?;