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()
)
);
}
```

Original writeup (https://teddyheinen.com/tenable-ctf-2020/#we-need-an-emulator).