use rebg::analyzer::dump::TraceDumper;
use rebg::analyzer::Analyzer;
use rebg::host::docker::{Docker, DockerArgs};
use rebg::host::native::{Native, NativeArgs};
use rebg::state::{Aarch64Step, Step, X64Step};
use rebg::tracer::qemu::QEMUParser;
use rebg::tracer::TracerCmd;
use rebg::{
arch::Arch,
host::Host,
tracer::{qemu::QEMU, Tracer},
};
use std::fmt;
use std::path::Path;
use std::{fs, path::PathBuf};
#[derive(argh::FromArgs)]
struct Arguments {
#[argh(positional)]
program: PathBuf,
#[argh(option, short = 'a')]
target_arch: Option<Arch>,
#[argh(subcommand)]
launcher: LauncherArgs,
}
#[derive(argh::FromArgs)]
#[argh(subcommand)]
enum LauncherArgs {
Docker(DockerArgs),
Native(NativeArgs),
}
impl LauncherArgs {
fn start_tracer(self, program: PathBuf, arch: Arch) -> Launchers {
match self {
LauncherArgs::Docker(x) => Launchers::Docker(x.start(program, arch)),
LauncherArgs::Native(x) => Launchers::Native(x.start()),
}
}
}
enum Launchers {
Docker(Docker),
Native(Native),
}
impl Host for Launchers {
type Error = anyhow::Error;
fn launch(
&self,
program: String,
args: Vec<String>,
) -> Result<std::process::Child, Self::Error> {
match self {
Launchers::Docker(d) => d.launch(program, args),
Launchers::Native(n) => n.launch(program, args),
}
}
fn read_file(&self, path: &std::path::Path) -> Result<Vec<u8>, Self::Error> {
match self {
Launchers::Docker(x) => x.read_file(path),
Launchers::Native(x) => x.read_file(path),
}
}
}
fn main() {
let Arguments {
program,
target_arch,
launcher,
} = argh::from_env();
let buffer = fs::read(&program).unwrap();
let elf = goblin::elf::Elf::parse(&buffer).unwrap();
let target_arch = target_arch.unwrap_or_else(|| Arch::from_elf(elf.header.e_machine).unwrap());
let qemu = QEMU {};
let launcher = launcher.start_tracer(program.clone(), target_arch);
match target_arch {
Arch::ARM64 => {
let parser =
launch_qemu::<_, _, Aarch64Step, 32>(&launcher, qemu, target_arch, &program);
TraceDumper::analyze::<_, _, QEMU, _, 32>(&launcher, parser, target_arch);
}
Arch::X86_64 => {
let parser = launch_qemu::<_, _, X64Step, 16>(&launcher, qemu, target_arch, &program);
TraceDumper::analyze::<_, _, QEMU, _, 16>(&launcher, parser, target_arch);
}
}
}
fn launch_qemu<LAUNCHER, TRACER, STEP, const N: usize>(
launcher: &LAUNCHER,
tracer: TRACER,
arch: Arch,
program: &Path,
) -> QEMUParser<STEP, N>
where
LAUNCHER: Host<Error = anyhow::Error>,
TRACER: Tracer<STEP, N, ITER = QEMUParser<STEP, N>>,
STEP: Step<N> + Send + 'static + fmt::Debug,
STEP: for<'a> TryFrom<&'a [String], Error = anyhow::Error>,
{
let cmd: TracerCmd<STEP, N> = tracer.command(program, arch);
let child = launcher.launch(cmd.program, cmd.args).unwrap();
tracer.parse(child)
}