use clap::{Parser, Subcommand}; use std::path::PathBuf; use std::process; /// A tool for extracting and inspecting Xbox 360 XEX2 executable files. #[derive(Parser)] #[command(name = "xex2tractor", version, about)] struct Cli { #[command(subcommand)] command: Command, } #[derive(Subcommand)] enum Command { /// Display XEX2 file information (headers, security info, etc.) Inspect { /// Path to the XEX2 file file: PathBuf, }, /// Extract the PE image from a XEX2 file Extract { /// Path to the XEX2 file file: PathBuf, /// Output path for the extracted PE file (default: same name with .exe extension) output: Option, }, } fn main() { let cli = Cli::parse(); match cli.command { Command::Inspect { file } => cmd_inspect(&file), Command::Extract { file, output } => cmd_extract(&file, output), } } fn cmd_inspect(path: &PathBuf) { let data = read_file(path); let xex = parse_xex(&data); xex2tractor::display::display_header(&xex.header); xex2tractor::display::display_optional_headers(&xex.optional_headers); xex2tractor::display::display_security_info(&xex.security_info); } fn cmd_extract(path: &PathBuf, output: Option) { let output_path = output.unwrap_or_else(|| path.with_extension("exe")); let data = read_file(path); let xex = parse_xex(&data); let pe_image = match xex2tractor::extract::extract_pe_image(&data, &xex) { Ok(img) => img, Err(e) => { eprintln!("Error extracting PE image: {e}"); process::exit(1); } }; // TODO(M6): verify PE headers before writing if let Err(e) = std::fs::write(&output_path, &pe_image) { eprintln!("Error writing {}: {e}", output_path.display()); process::exit(1); } println!("Extracted PE image to {}", output_path.display()); println!(" Input: {} ({} bytes)", path.display(), data.len()); println!(" Output: {} ({} bytes)", output_path.display(), pe_image.len()); } fn read_file(path: &PathBuf) -> Vec { match std::fs::read(path) { Ok(d) => d, Err(e) => { eprintln!("Error reading {}: {e}", path.display()); process::exit(1); } } } fn parse_xex(data: &[u8]) -> xex2tractor::Xex2File { match xex2tractor::parse(data) { Ok(x) => x, Err(e) => { eprintln!("Error parsing XEX2: {e}"); process::exit(1); } } }