Files
xex2tractor/src/main.rs
MechaCat02 c665868b1b feat: add PE image decompression and extraction pipeline (M5)
Implement full decrypt + decompress pipeline for XEX2 PE extraction:
- decompress.rs: None, Basic (zero-fill), and Normal (LZX) decompression
- extract.rs: orchestrates decryption then decompression
- Wire up CLI extract command to write PE files
- LZX decompression via lzxd crate with per-frame chunk processing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 21:48:23 +01:00

91 lines
2.5 KiB
Rust

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<PathBuf>,
},
}
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<PathBuf>) {
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<u8> {
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);
}
}
}