about summary refs log tree commit diff
path: root/src/main.rs
blob: 34f73e189d5e91dbdb41137634d84ecd529da70e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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(())
}