Tags: emulation code
Rating:
Not much to say here -- we got a toy architecture with three operations (MOV, REVERSE, and XOR) as well as two registers (TRX and DRX). I solved it in Rust.
```rust
/*
[package]
name = "tenable-emu"
version = "0.1.0"
authors = ["Teddy Heinen <[email protected]>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nom = "6.1.2"
*/
use nom::branch::alt;
use nom::bytes::complete::{tag, take_until};
use nom::combinator::opt;
use nom::multi::many1;
use nom::{Finish, IResult};
use std::collections::HashMap;
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
enum Register {
Trx,
Drx,
}
#[derive(Debug, Clone)]
enum Instruction {
Xor(Register, Register),
MovL(Register, String),
Mov(Register, Register),
Reverse(Register),
}
fn instruction(input: &str) -> IResult<&str, Instruction> {
fn register(input: &str) -> IResult<&str, Register> {
fn trx(input: &str) -> IResult<&str, Register> {
let (input, _) = tag("TRX")(input)?;
Ok((input, Register::Trx))
}
fn drx(input: &str) -> IResult<&str, Register> {
let (input, _) = tag("DRX")(input)?;
Ok((input, Register::Drx))
}
alt((trx, drx))(input)
}
fn xor(input: &str) -> IResult<&str, Instruction> {
let (input, _) = tag("XOR ")(input)?;
let (input, lhs) = register(input)?;
let (input, _) = tag(" ")(input)?;
let (input, rhs) = register(input)?;
let (input, _) = opt(tag("\r\n"))(input)?;
Ok((input, Instruction::Xor(lhs, rhs)))
}
fn movl(input: &str) -> IResult<&str, Instruction> {
let (input, _) = tag("MOV ")(input)?;
let (input, lhs) = register(input)?;
let (input, _) = tag(" \"")(input)?;
let (input, rhs) = take_until("\"")(input)?;
let (input, _) = tag("\"")(input)?;
let (input, _) = opt(tag("\r\n"))(input)?;
Ok((input, Instruction::MovL(lhs, rhs.to_string())))
}
fn mov(input: &str) -> IResult<&str, Instruction> {
let (input, _) = tag("MOV ")(input)?;
let (input, lhs) = register(input)?;
let (input, _) = tag(" ")(input)?;
let (input, rhs) = register(input)?;
let (input, _) = opt(tag("\r\n"))(input)?;
Ok((input, Instruction::Mov(lhs, rhs)))
}
fn reverse(input: &str) -> IResult<&str, Instruction> {
let (input, _) = tag("REVERSE ")(input)?;
let (input, lhs) = register(input)?;
let (input, _) = opt(tag("\r\n"))(input)?;
Ok((input, Instruction::Reverse(lhs)))
}
alt((xor, movl, mov, reverse))(input)
}
#[derive(Debug, Default, Clone)]
struct State {
registers: HashMap<Register, Vec<u8>>,
}
impl State {
fn apply(&mut self, instr: Instruction) -> &mut Self {
match instr {
Instruction::Xor(lhs, rhs) => {
let lhs_reg = self.registers.get(&lhs).unwrap().clone();
let rhs_reg = self.registers.get(&rhs).unwrap().clone();
let new_val = lhs_reg
.into_iter()
.enumerate()
.map(|(index, x)| x ^ rhs_reg.get(index).unwrap_or(&0u8))
.collect::<Vec<_>>();
self.registers.insert(lhs, new_val);
}
Instruction::MovL(lhs, rhs) => {
self.registers.insert(lhs, rhs.bytes().collect());
}
Instruction::Mov(lhs, rhs) => {
let rhs_reg = self.registers.get(&rhs).unwrap().clone();
self.registers.insert(lhs, rhs_reg);
}
Instruction::Reverse(lhs) => {
let lhs_reg = self.registers.get(&lhs).unwrap().clone();
self.registers
.insert(lhs, lhs_reg.iter().cloned().rev().collect::<Vec<_>>());
}
};
self
}
}
fn main() {
let crypto = include_str!("../../Crypto.asm");
let (_, instructions) = many1(instruction)(crypto).finish().unwrap();
let mut state = State::default();
state
.registers
.insert(Register::Trx, b"GED\x03hG\x15&Ka =;\x0c\x1a31o*5M".to_vec());
state.registers.insert(Register::Drx, b"".to_vec());
println!(
"{:?}",
String::from_utf8_lossy(
&instructions
.into_iter()
.fold(&mut state, |st, instr| st.apply(instr))
.registers
.get(&Register::Trx)
.unwrap()
.clone()
)
);
}
```