From 94ce29d4dedafbc5a07f0425935c9d08e992c42f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Wed, 17 Apr 2024 22:49:47 +0200 Subject: [PATCH] feat: improve cli tool --- enmacompat/README.md | 19 ++++++++++++ enmacompat/src/lib.rs | 1 + enmacompat/src/main.rs | 66 +++++++++++++++++++++++++----------------- enmacompat/src/meta.rs | 47 ++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 27 deletions(-) create mode 100644 enmacompat/README.md create mode 100644 enmacompat/src/meta.rs diff --git a/enmacompat/README.md b/enmacompat/README.md new file mode 100644 index 0000000..1e2b3ae --- /dev/null +++ b/enmacompat/README.md @@ -0,0 +1,19 @@ +# Enma Compat + +Library with CLI tool to work with Enma Engine's emedded data + +## CLI + +You can use the CLI to inspect data contained in the binary + +```sh +# Only need to run this once +enmacompat --path path/to/exe analyze + +# This is for inspecting +enmacompat --path path/to/exe extract +``` + +## Blender Script + +TODO; diff --git a/enmacompat/src/lib.rs b/enmacompat/src/lib.rs index f104293..77a4063 100644 --- a/enmacompat/src/lib.rs +++ b/enmacompat/src/lib.rs @@ -1,4 +1,5 @@ pub mod area; +pub mod meta; pub mod section; mod util; pub mod windows_pe; diff --git a/enmacompat/src/main.rs b/enmacompat/src/main.rs index 2497ba2..107f9b3 100644 --- a/enmacompat/src/main.rs +++ b/enmacompat/src/main.rs @@ -1,44 +1,56 @@ -use clap::{command, Parser}; -use enmacompat::{ - area::{find_area_array_location, read_area, EnmaAreaRaw}, - windows_pe::WindowsPEFile, -}; +use clap::{command, Parser, Subcommand}; +use enmacompat::{area::read_area, meta::EnmaMeta, windows_pe::WindowsPEFile}; use std::fs::File; -#[derive(Parser, Debug)] +#[derive(Parser)] #[command(version, about)] struct Args { + #[clap(subcommand)] + command: Commands, + #[clap(short, long)] path: std::path::PathBuf, } +#[derive(Subcommand)] +enum Commands { + #[clap(about = "Analyze the file and generate a metadata file")] + Analyze, + #[clap(about = "Extract data from the file")] + Extract, +} + fn main() { let args = Args::parse(); let file = File::open(&args.path).expect("Failed to open file"); let mut windows_pe_file = WindowsPEFile::from(file); - println!("\x1b[34m\x1b[1mSearching for Area Array Location\x1b[0m"); - let location = Some(0x1417cc980); //find_area_array_location(&mut windows_pe_file).unwrap(); - if let Some(location) = location { - println!( - "\x1b[32m\x1b[1mArea Array Location\x1b[0m: \x1b[4m{:#x}\x1b[0m (Memory), \x1b[4m{:#x}\x1b[0m (File)", - location, - windows_pe_file.get_file_address(location).unwrap() - ); - - let mut i = 1; - loop { - let address = windows_pe_file.read_addr::(location + i * 8).unwrap(); - if address == 0 { - break; - } - let area = read_area(&windows_pe_file, address).unwrap(); - let file = File::create(format!("out/{}.json", area.name)).unwrap(); + match args.command { + Commands::Analyze => { + let file = File::create(args.path.with_extension("json")).unwrap(); let mut writer = std::io::BufWriter::new(file); - serde_json::to_writer_pretty(&mut writer, &area).unwrap(); - i += 1; + serde_json::to_writer_pretty( + &mut writer, + &EnmaMeta::from_analysis(&mut windows_pe_file).unwrap(), + ) + .unwrap(); + } + Commands::Extract => { + let meta_file = File::open(args.path.with_extension("json")) + .expect("Missing meta file, did you forget to run the analyze command?"); + let meta: EnmaMeta = serde_json::from_reader(meta_file) + .expect("Failed to read meta file, try running the analyze command again?"); + + for i in 1..meta.area_array_count { + let address = windows_pe_file + .read_addr::(meta.area_array_addr + i as u64 * 8) + .unwrap(); + + let area = read_area(&windows_pe_file, address).unwrap(); + let file = File::create(format!("out/{}.json", area.name)).unwrap(); + let mut writer = std::io::BufWriter::new(file); + serde_json::to_writer_pretty(&mut writer, &area).unwrap(); + } } - } else { - println!("\x1b[31mArea array location could not found\x1b[0m"); } } diff --git a/enmacompat/src/meta.rs b/enmacompat/src/meta.rs new file mode 100644 index 0000000..d937d1f --- /dev/null +++ b/enmacompat/src/meta.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; + +use crate::{area::find_area_array_location, windows_pe::WindowsPEFile}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct EnmaMeta { + pub area_array_addr: u64, + pub area_array_count: i32, +} + +impl EnmaMeta { + /// Performs an analysis from a WindowsPE executable to find specific data locations + pub fn from_analysis(windows_pe_file: &mut WindowsPEFile) -> Result { + println!("\x1b[34m\x1b[1mSearching for Area Array Location\x1b[0m"); + let area_array_addr = find_area_array_location(windows_pe_file)?.ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::NotFound, + "Could not find Area Array Location", + ) + })?; + + let mut area_array_count = 1; + loop { + let area_array = + windows_pe_file.read_addr::(area_array_addr + area_array_count as u64 * 8)?; + if area_array == 0 { + break; + } + + let id = windows_pe_file.read_addr::(area_array)?; + if id != area_array_count as u64 { + break; + } + area_array_count += 1; + } + + println!( + "\x1b[32m\x1b[1mArea Array\x1b[0m: \x1b[4m{:#x} ({} items)\x1b[0m", + area_array_addr, area_array_count + ); + + Ok(Self { + area_array_addr, + area_array_count, + }) + } +}