diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..34f73e1 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,179 @@ +use r2pipe::R2Pipe; +use structopt::StructOpt; +use std::path::PathBuf; +use std::time::Duration; + +// we're using a custom int type here, as we want to set defaults using +// structopt which leads to a problem, as structopt only allows strings to be +// set as default values () +#[derive(Debug)] +struct Int(u64); + +impl std::str::FromStr for Int { + type Err = Box<dyn std::error::Error>; + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Int(s.parse::<u64>().unwrap())) + } +} +impl std::fmt::Display for Int { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +// we're using a custom "Delay" type here, as we want to define the duration +// #of a game round, but structopt (as with the int stuff above) can't use time +// durations (it's time, not easy!). [derive(Debug)] +#[derive(Debug)] +struct Delay(Duration); + +impl std::str::FromStr for Delay { + type Err = Box<dyn std::error::Error>; + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Delay(Duration::from_secs(s.parse::<u64>().unwrap()))) + } +} + +#[derive(Debug)] +struct Bot { + // Path defines the path to the source of the bot + path: PathBuf, + + // Source defines the source of the bot after being compiled with rasm2 + source: Option<String>, + + // Addr defines the initial address the bot is placed at + addr: Option<u64>, + + // Regs defines the state of the registers of the bot + // It is used to store the registers after each round and restore them in the + // next round when the bot's turn has come + regs: Option<String>, +} + +#[derive(Debug, PartialEq, Clone)] +struct BotPaths(Vec<String>); + +impl std::str::FromStr for BotPaths { + type Err = Box<dyn std::error::Error>; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(BotPaths(s.split(",").map(|x| x.trim().to_owned()).collect())) + } +} + +// these are the options you can use, list them nicely using +// `cargo run -- --help` +#[derive(Debug, StructOpt)] +#[structopt(about = "Yet another r2wars implementation, made with <3 @ AFRA Berlin")] +struct Opt { + + #[structopt(short = "a", long = "arch", default_value = "x86")] + architecture: String, + + #[structopt(short = "b", long = "bits", default_value = "64")] + bits: Int, + + #[structopt(long = "memsize", default_value = "4096")] + memory_size: Int, + + #[structopt(long = "maxbotsize", default_value = "256")] + max_bot_size: Int, + + #[structopt(long = "bots", default_value = "bots/warrior0.asm, bots/warrior1.asm")] + bots: BotPaths, + + #[structopt(long = "delay", default_value = "1")] + game_round_duration_seconds: Delay, +} + +fn init_arena(r2p: &mut R2Pipe, opt: &Opt) { + println!("[ ] Initializing the arena"); + println!("[ ] Allocating {} bytes of memory...", opt.memory_size); + + let _ = r2p.cmd(format!("malloc://{}", opt.memory_size).as_str()) + .expect("could not allocate memory"); + + println!("[ ] General configuration..."); + let _ = r2p.cmd(format!("e asm.arch = {}", opt.architecture).as_str()) + .expect("could not set the desired architecture"); + let _ = r2p.cmd(format!("e asm.bits = {}", opt.bits).as_str()) + .expect("could not set the desired bits"); + println!("[ ] ...Done"); + + println!("[ ] Theming..."); + let _ = r2p.cmd("e scr.color = 3").expect("set color err"); + let _ = r2p.cmd("e scr.color.args = true").expect("set color err"); + let _ = r2p.cmd("e scr.color.bytes = true").expect("set color err"); + let _ = r2p.cmd("e scr.color.grep = true").expect("set color err"); + let _ = r2p.cmd("e scr.color.ops = true").expect("set color err"); + let _ = r2p.cmd("e scr.color.pipe = true").expect("set color err"); + let _ = r2p.cmd("e scr.bgfill = true").expect("set color err"); + let _ = r2p.cmd("e scr.utf8 = true").expect("set color err"); + let _ = r2p.cmd("e hex.cols = 32").expect("set hex col width err"); + println!("[ ] ...Done"); + + println!("[ ] ESIL..."); + let _ = r2p.cmd("aei").expect("init esil vm failed"); // init ESIL VM + let _ = r2p.cmd("aeim").expect("init esil vm stack failed"); // init ESIL VM stack + println!("[ ] ...Done"); +} + +fn build_bots(opt: &Opt, bots: &mut Vec<Bot>) { + for bot_path in opt.bots.0.clone().into_iter() { + bots.push( + build_bot(PathBuf::from(bot_path)) + .expect("could not build a bot!") + ) + } +} + +fn build_bot(bot_path: PathBuf) -> Result<Bot, ()> { + + let mut r2p = r2pipe::open_pipe!(Some("--").to_owned()).expect("could not open r2pipe"); + + let source = r2p.cmd(format!("rasm2 -a {} -b {} -f {:?}", "x86", "32", bot_path).as_str()) + .expect("failed to build the bot!"); + + let new_bot: Bot = Bot { + path: bot_path, + source: Some(source), + addr: None, + regs: None, + }; + + Ok(new_bot) +} + +fn main() -> Result<(), Box<dyn std::error::Error>> { + let mut bots: Vec<Bot> = vec![]; + + let opt = Opt::from_args(); + + println!("{:?}", opt.architecture); + println!("{:?}", opt.bits); + println!("{:?}", opt.memory_size); + println!("{:?}", opt.max_bot_size); + println!("{:?}", opt.bots); + println!("{:?}", opt.game_round_duration_seconds); + + let path = Some("/Users/emilehansmaennel/Documents/CTF/2023/indore/Lengan/main_fixed".to_owned()); + let mut r2p = r2pipe::open_pipe!(path).expect("could not open r2pipe"); + + init_arena(&mut r2p, &opt); + + build_bots(&opt, &mut bots); + + for bot in bots { + println!("{:?}", bot); + } + + // println!("{}", r2p.cmd("?e Hello World").expect("could not exec command")); + // println!("{}", r2p.cmd("aaa").expect("could not exec command")); + // println!("---"); + // println!("{}", r2p.cmd("afl").expect("could not exec command")); + // println!("---"); + r2p.close(); + + Ok(()) +} |