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,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(())
|
||||
|
@@ -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(())
|
||||
|
@@ -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(), "_")
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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)?;
|
||||
|
||||
|
Reference in New Issue
Block a user