mirror of
https://github.com/Theaninova/WanganSunrise.git
synced 2025-12-11 02:56:17 +00:00
feat: improve cli tool
This commit is contained in:
19
enmacompat/README.md
Normal file
19
enmacompat/README.md
Normal file
@@ -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;
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod area;
|
||||
pub mod meta;
|
||||
pub mod section;
|
||||
mod util;
|
||||
pub mod windows_pe;
|
||||
|
||||
@@ -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::<u64>(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::<u64>(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");
|
||||
}
|
||||
}
|
||||
|
||||
47
enmacompat/src/meta.rs
Normal file
47
enmacompat/src/meta.rs
Normal file
@@ -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<Self, std::io::Error> {
|
||||
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::<u64>(area_array_addr + area_array_count as u64 * 8)?;
|
||||
if area_array == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let id = windows_pe_file.read_addr::<u64>(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,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user