Skip to content

Instantly share code, notes, and snippets.

@markusl
Last active September 28, 2015 20:17
Show Gist options
  • Save markusl/1490780 to your computer and use it in GitHub Desktop.
Save markusl/1490780 to your computer and use it in GitHub Desktop.
GCHQ Challenge Stage 2
/// Implementation for GCHQ Challenge stage 2 virtual machine, in F#
/// From: http://canyoucrackit.co.uk/codeexplained.asp?v=1
/// This is a JavaScript programming challenge, with a cyber security angle. To solve
/// this stage an implementation of a simple virtual processor is required. Some notes
/// on the architecture are provided along with a block of data that can be analysed.
/// Solving this stage will reveal the final stage of the challenge.
/// The challenge originally suggested writing a virtual machine for the given instructions in JavaScript, but I decided to go with F#
/// See original 15b436de1f9107f3778aad525e5d0b20.js at http://pastebin.com/p5AHwPra
///
/// This implementation contains three files:
/// - GCHQ_vm.fs, The main VM implementation
/// - GCHQ_vm_test.fs, Some NUnit (FsUnit) tests for the VM code
/// - Program.fs, The main program which runs the given instruction array with the VM
///
/// Only for entertainment purposes :-)
/// -Markus Lindqvist 2011
module GCHQ
// opcode | instruction | operands (mod 0) | operands (mod 1)
// -------+-------------+------------------+-----------------
// 0x00 | jmp | r1 | r2:r1
// 0x01 | movr | r1, r2 | rx, imm
// 0x02 | movm | r1, [ds:r2] | [ds:r1], r2
// 0x03 | add | r1, r2 | r1, imm
// 0x04 | xor | r1, r2 | r1, imm
// 0x05 | cmp | r1, r2 | r1, imm
// 0x06 | jmpe | r1 | r2:r1
// 0x07 | hlt | N/A | N/A
type OpCodes =
| op_jmp = 0x00
| op_movr = 0x01
| op_movm = 0x02
| op_add = 0x03
| op_xor = 0x04
| op_cmp = 0x05
| op_jmpe = 0x06
| op_hlt = 0x07
/// Segmented memory model with 16-byte segment size (notation seg:offset)
let seg_size = 16
/// Total memory size
let memory_size = 16*256
type Registers =
| R0 = 0 /// 4 general-purpose registers (r0-r3)
| R1 = 1 /// 4 general-purpose registers (r0-r3)
| R2 = 2 /// 4 general-purpose registers (r0-r3)
| R3 = 3 /// 4 general-purpose registers (r0-r3)
| R4 = 4 | CS = 4 /// Code Segment register index (r4)
| R5 = 5 | DS = 5 /// Data Segment register index (r5)
type Cpu = {
ip : int
registers : int []
fl : int /// 1 flags register (fl)
} with
member x.reg with get (register:Registers) = x.registers.[int register]
and set (register:Registers) va = x.registers.[int register] <- va
override x.ToString() = sprintf "r0-r5: %x, %x, %x, %x, %x, %x, fl=%d, ip=%x" x.registers.[0] x.registers.[1] x.registers.[2] x.registers.[3] x.registers.[4] x.registers.[5] x.fl x.ip
static member New = { new Cpu
with ip = 0
and registers = Array.create<int> 6 0
and fl = 0
}
type Mem = {
memory : int []
} with
static member Empty = { new Mem
with memory = Array.create<int> memory_size 0
}
type Vm = {
mem : Mem
cpu : Cpu
} with
member x.current_instruction =
x.mem.memory.[x.cpu.reg Registers.CS*16 + x.cpu.ip]
member x.current_opcode =
enum<OpCodes>((x.current_instruction>>>5)&&&(0x7))
member x.current_modifier = (x.current_instruction>>>4)&&&(0x1)
member x.next_instruction =
x.mem.memory.[x.cpu.reg Registers.CS*16 + x.cpu.ip+1]
static member New = { new Vm
with mem = Mem.Empty
and cpu = Cpu.New }
static member WithMemory (mem_:int []) = { new Vm
with mem = {new Mem with memory = mem_}
and cpu = Cpu.New
}
let log func cpu =
let obj = (new System.Diagnostics.StackFrame(1)).GetMethod().DeclaringType.Name
let str = sprintf "%s:%s\t\t\tcpu=[%s]" obj func (cpu.ToString())
System.Diagnostics.Debug.WriteLine(str)
let opCodeNop (cpu:Cpu) (mem:Mem) = cpu,mem
let opCodeJmpR1(r1) (cpu:Cpu) (mem:Mem) =
log "jmp1" cpu
{cpu with ip = cpu.registers.[r1]},mem
let opCodeJmpR1R2(r1, r2) (cpu:Cpu) (mem:Mem) =
log "jmp2" cpu
cpu.registers.[int Registers.CS] <- r2
{cpu with ip = cpu.registers.[r1]}, mem
let opCodeJmpeR1(r1) (cpu:Cpu) (mem:Mem) =
log "jmpe1" cpu
if cpu.fl = 0 then
opCodeJmpR1 r1 cpu mem
else
cpu,mem
let opCodeJmpeR1R2(r1, r2) (cpu:Cpu) (mem:Mem) =
log "jmpe2" cpu
if cpu.fl = 0 then
opCodeJmpR1R2 (r1, r2) cpu mem
else
cpu,mem
let opCodeCmp(r1, r2) (cpu:Cpu) (mem:Mem) =
log "cmp" cpu
let fl = if cpu.registers.[r1] = r2 then 0
else if cpu.registers.[r1] < r2 then 0xff
else 1
{cpu with fl = fl},mem
let opCodeMovr(r1, imm) (cpu:Cpu) (mem:Mem) =
log "movr" cpu
cpu.registers.[r1] <- imm
cpu,mem
let opCodeMovmMod0(r1, r2) (cpu:Cpu) (mem:Mem) =
log "movm0" cpu
cpu.registers.[r1] <- mem.memory.[cpu.reg Registers.DS*seg_size + cpu.registers.[r2]]
cpu,mem
let opCodeMovmMod1(r1, r2) (cpu:Cpu) (mem:Mem) =
log "movm1" cpu
mem.memory.[cpu.reg Registers.DS*seg_size + cpu.registers.[r1]] <- cpu.registers.[r2]
cpu,mem
let opCodeAdd(r1, imm) (cpu:Cpu) (mem:Mem) =
log "add" cpu
cpu.registers.[int r1] <- cpu.registers.[int r1] + imm &&& 0xFF
cpu,mem
let opCodeXor(r1, imm) (cpu:Cpu) (mem:Mem) =
log "xor" cpu
cpu.registers.[int r1] <- cpu.registers.[int r1] ^^^ imm
cpu,mem
// cmp r1, r2 instruction results in:
// r1 == r2 => fl = 0
// r1 < r2 => fl = 0xff
// r1 > r2 => fl = 1
// instruction encoding
// ++++++++++++++++++++
//
// byte 1 byte 2 (optional)
// bits [ 7 6 5 4 3 2 1 0 ] [ 7 6 5 4 3 2 1 0 ]
// opcode - - -
// mod -
// operand1 - - - -
// operand2 - - - - - - - -
//
// operand1 is always a register index
// operand2 is optional, depending upon the instruction set specified below
// the value of mod alters the meaning of any operand2
// 0: operand2 = reg ix
// 1: operand2 = fixed immediate value or target segment (depending on instruction)
/// Check if given opcode is jump instruction
let is_jump opcode = match opcode with | OpCodes.op_jmp | OpCodes.op_jmpe -> true
| _ -> false
/// Decode current opcode (at CS:IP)
let decode_opcode (vm:Vm) =
let byte1 = vm.current_instruction
let opcode = vm.current_opcode
let operand1 = (byte1)&&&(0xF)
let read_operand2 =
if (is_jump opcode) && vm.current_modifier = 0 then None
else Some(vm.next_instruction)
match (opcode, vm.current_modifier) with
| (OpCodes.op_jmp, 0) -> opCodeJmpR1(operand1)
| (OpCodes.op_jmp, 1) -> opCodeJmpR1R2(operand1, read_operand2_val)
| (OpCodes.op_jmpe, 0) -> opCodeJmpeR1(operand1)
| (OpCodes.op_jmpe, 1) -> opCodeJmpeR1R2(operand1, read_operand2_val)
| (OpCodes.op_movm, 0) -> opCodeMovmMod0(operand1, vm.next_instruction)
| (OpCodes.op_movm, 1) -> opCodeMovmMod1(operand1, vm.next_instruction)
| (OpCodes.op_movr, _) -> opCodeMovr(operand1, read_operand2_val)
| (OpCodes.op_add, _) -> opCodeAdd(operand1, read_operand2_val)
| (OpCodes.op_xor, _) -> opCodeXor(operand1, read_operand2_val)
| (OpCodes.op_cmp, _) -> opCodeCmp(operand1, read_operand2_val)
| (OpCodes.op_hlt, _) -> opCodeNop
| _ -> failwith (sprintf "Unknown opcode: %d" (int opcode))
/// Run the virtual machine until a op_halt is encountered
let rec run_vm (vm:Vm) =
let opcode = decode_opcode vm
if vm.current_opcode = OpCodes.op_hlt then vm
else
let get_ip_increase =
if (is_jump vm.current_opcode) && vm.current_modifier = 0 then 1
else 2
let cpu_with_ip = {vm.cpu with ip = vm.cpu.ip + get_ip_increase &&& 0xFF}
let cpu, mem = opcode cpu_with_ip vm.mem
run_vm {vm with cpu = cpu; mem = mem}
module GCHQ_vm_tests
open NUnit.Framework
open FsUnit
open GCHQ
[<TestFixture>]
type ``Cpu construction tests``() =
let cpu = Cpu.New
[<Test>] member test.``Flags are initialized to zero``() =
cpu.fl |> should equal 0
[<Test>] member test.``Instruction pointer is initialized to zero``() =
cpu.ip |> should equal 0
[<Test>] member test.``Has six registers``() =
cpu.registers |> should haveLength 6
[<TestFixture>]
type ``OpCode Nop test``() =
let cpu = Cpu.New
let mem = Mem.Empty
[<Test>] member test.``Opcode does nothing``() =
let (cpu, mem) = opCodeNop cpu mem
mem |> should equal Mem.Empty
cpu.ip |> should equal 0
[<TestFixture>]
type ``OpCode Xor test``() =
let cpu = Cpu.New
let mem = Mem.Empty
[<Test>] member test.``xor's given value with value in register and and stores in the register``() =
let reg = Registers.R2
cpu.registers.[int reg] <- 13
let (cpu, mem) = opCodeXor (int reg, 77) cpu mem
Assert.AreEqual(mem, Mem.Empty)
Assert.AreNotEqual(cpu.registers, Cpu.New.registers)
Assert.AreEqual(cpu.ip, 0)
Assert.AreEqual(cpu.registers.[int reg], 77^^^13)
[<TestFixture>]
type ``OpCode Add test``() =
let cpu = Cpu.New
let mem = Mem.Empty
[<Test>] member test.``xor's given value with value in register and and stores in the register``() =
let reg = Registers.R4
cpu.registers.[int reg] <- 13
let (cpu, mem) = opCodeAdd(int reg, 77) cpu mem
mem |> should equal Mem.Empty
cpu.registers |> should not (equal Cpu.New.registers)
cpu.ip |> should equal 0
cpu.registers.[int reg] |> should equal (77+13)
[<TestFixture>]
type ``OpCode Jmp test``() =
let cpu = Cpu.New
let mem = {new Mem with memory = [|0x40; 0x02|]}
[<Test>] member test.``Jmp instruction changes jumps to location specified in register``() =
cpu.reg Registers.R0 <- 0x213
let (cpu, mem) = opCodeJmpR1(int Registers.R0) cpu mem
cpu.reg Registers.CS |> should equal (Cpu.New.reg Registers.CS)
cpu.ip |> should equal 0x213
[<Test>] member test.``Jmpr instruction changes code segment``() =
let vm = Vm.WithMemory([|0x31; 0x04|])
vm.cpu.reg Registers.R1 <- 0xA1
let (cpu, mem) = opCodeJmpR1R2(int Registers.R1, 0x04) vm.cpu vm.mem
cpu.reg Registers.CS |> should equal 0x04
cpu.ip |> should equal 0xA1
[<Test>] member test.``Jmpr instruction changes code segment again``() =
let vm = Vm.WithMemory([|0x33; 0xaa|])
let (cpu, mem) = opCodeJmpR1R2(int Registers.R1, 0xaa) vm.cpu vm.mem
cpu.reg Registers.CS |> should equal 0xaa
cpu.ip |> should equal 0
[<TestFixture>]
type ``OpCode Cmp test``() =
[<Test>] member test.``set fl to zero if equal``() =
let cpu = {Cpu.New with fl = 1}
cpu.reg Registers.R3 <- 999
let (cpu, mem) = opCodeCmp(3, 999) cpu Mem.Empty
mem |> should equal Mem.Empty
cpu.fl |> should equal 0
[<Test>] member test.``set fl to 0xff if less than``() =
let cpu = {Cpu.New with fl = 88}
cpu.reg Registers.R2 <- 997
let (cpu, mem) = opCodeCmp(int Registers.R2, 998) cpu Mem.Empty
mem |> should equal Mem.Empty
cpu.fl |> should equal 0xff
[<Test>] member test.``set fl to 1 if more than``() =
let cpu = {Cpu.New with fl = 88}
cpu.reg Registers.R1 <- 998
let (cpu, mem) = opCodeCmp(int Registers.R1, 997) cpu Mem.Empty
mem |> should equal Mem.Empty
cpu.fl |> should equal 1
[<TestFixture>]
type ``OpCode Movr test``() =
let cpu = Cpu.New
let mem = Mem.Empty
let move_and_verify reg value =
let (cpu, mem) = opCodeMovr(int reg, value) cpu mem
mem |> should equal Mem.Empty
cpu.ip |> should equal Cpu.New.ip
cpu.fl |> should equal Cpu.New.fl
cpu.reg reg |> should equal value
[<Test>] member test.``move value to R2``() =
move_and_verify Registers.R2 999
[<Test>] member test.``move negative value to DS``() =
move_and_verify Registers.DS -1
[<TestFixture>]
type ``OpCode Movm test``() =
let cpu = Cpu.New
let mem = Mem.Empty
let move_mem_to_reg reg_to reg_from value cpu mem =
let (cpu, mem) = opCodeMovmMod0(int reg_to, int reg_from) cpu mem
cpu.ip |> should equal Cpu.New.ip
cpu.fl |> should equal Cpu.New.fl
cpu.reg reg_to |> should equal value
let move_reg_to_mem reg_to reg_from value cpu mem idx =
let (cpu, mem) = opCodeMovmMod1(int reg_to, int reg_from) cpu mem
cpu.ip |> should equal Cpu.New.ip
cpu.fl |> should equal Cpu.New.fl
mem.memory.[idx] |> should equal value
[<Test>] member test.``move from mem to reg``() =
mem.memory.[0xA*16 + 0xB] <- 0xFF
cpu.reg Registers.DS <- 0xA
cpu.reg Registers.R2 <- 0xB
move_mem_to_reg Registers.R1 Registers.R2 0xFF cpu mem
[<Test>] member test.``move from mem to reg, negative value``() =
mem.memory.[0xFF*16 + 0x0] <- -1
cpu.reg Registers.DS <- 0xFF
cpu.reg Registers.R0 <- 0x0
move_mem_to_reg Registers.R3 Registers.R0 -1 cpu mem
[<Test>] member test.``move from reg to mem``() =
cpu.reg Registers.DS <- 0xA
cpu.reg Registers.R1 <- 0xB
cpu.reg Registers.R2 <- 0xFF
move_reg_to_mem Registers.R1 Registers.R2 0xFF cpu mem (0xA*16 + 0xB)
[<Test>] member test.``move from reg to mem, negative value``() =
cpu.reg Registers.DS <- 0x0E
cpu.reg Registers.R2 <- 0xF1
cpu.reg Registers.R0 <- -1
move_reg_to_mem Registers.R2 Registers.R0 -1 cpu mem (0x0E*16 + 0xF1)
[<TestFixture>]
type ``OpCode Jmpe test``() =
let cpu = Cpu.New
let mem = {new Mem with memory = [|0x40; 0x02|]}
let cpu_with_fl_not_zero =
let cpu = {Cpu.New with fl = 1}
cpu.reg Registers.R0 <- 0x213
cpu.reg Registers.R1 <- 0xA1
cpu
[<Test>] member test.``JmpeR1 instruction does not change code segment``() =
let cpu = cpu_with_fl_not_zero
cpu.reg Registers.CS |> should equal 4
let (cpu, mem) = opCodeJmpR1(int Registers.R0) cpu mem
cpu.reg Registers.CS |> should equal 4
cpu.ip |> should equal 0x213
[<Test>] member test.``Jmpe does nothing if fl is not zero``() =
let cpu = cpu_with_fl_not_zero
let (cpu, mem) = opCodeJmpeR1(int Registers.R0) cpu mem
cpu.registers |> should equal (cpu_with_fl_not_zero.registers)
cpu.ip |> should equal (cpu_with_fl_not_zero.ip)
[<Test>] member test.``Jmpe instruction does nothing if fl is not zero``() =
let cpu = cpu_with_fl_not_zero
cpu.reg Registers.R1 <- 0xA1
cpu.reg Registers.R3 <- 0x04
let (cpu, mem) = opCodeJmpeR1R2(int Registers.R1, int Registers.R3) cpu mem
cpu.registers |> should equal (cpu_with_fl_not_zero.registers)
cpu.ip |> should equal (cpu_with_fl_not_zero.ip)
[<Test>] member test.``Jmpe instruction changes code segment``() =
let cpu = cpu_with_fl_not_zero
let (cpu, mem) = opCodeJmpR1R2(int Registers.R1, 0x04) cpu mem
cpu.reg Registers.CS |> should equal 0x04
cpu.ip |> should equal 0xA1
[<TestFixture>]
type ``Run OpCode``() =
let runCode mem =
let vm = Vm.WithMemory(mem)
run_vm vm
[<Test>] member test.``Run Halt instruction``() =
let vm = runCode [|0xf2; 0xb1|]
vm.cpu.ip |> should equal 0
[<Test>] member test.``Run Movr instruction with mod=1``() =
let vm = runCode [|0x31; 0x04; 0xe3; 0x00|]
vm.cpu.ip |> should equal 2
[<Test>] member test.``Run Movr instruction with mod=0``() =
let vm = runCode [|64; 2; 0xe3; 0x00|]
vm.cpu.ip |> should equal 2
[<Test>] member test.``Run Xor instruction with mod=0``() =
let vm = runCode [|128; 3; 0xe3; 0x00|]
vm.cpu.ip |> should equal 2
[<Test>] member test.``Run Movm instruction with mod=1``() =
let vm = runCode [|82; 0; 0xe3; 0x00|]
vm.cpu.ip |> should equal 2
[<Test>] member test.``Run add instruction with mod=1``() =
let vm = runCode [|114; 1; 0xe3; 0x00|]
vm.cpu.ip |> should equal 2
[<Test>] member test.``Run JmpR1 instruction``() =
let vm = Vm.WithMemory([|2; 128; 0xe3; 0x00; 0xe3; 0x00|])
vm.cpu.reg Registers.R2 <- 4
let vm = run_vm vm
vm.cpu.ip |> should equal 4
[<Test>] member test.``Run JmpR1R2 instruction``() =
let vm = Vm.WithMemory([|0x10; 0x00; 0xe3; 0x00; 0xe3; 0x00|])
vm.cpu.reg Registers.R0 <- 4
let vm = run_vm vm
vm.cpu.ip |> should equal 4
module Program
open GCHQ
// http://pastebin.com/p5AHwPra
let mem = [|0x31; 0x04; 0x33; 0xaa; 0x40; 0x02; 0x80; 0x03; 0x52; 0x00; 0x72; 0x01; 0x73; 0x01; 0xb2; 0x50;
0x30; 0x14; 0xc0; 0x01; 0x80; 0x00; 0x10; 0x10; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x98; 0xab; 0xd9; 0xa1; 0x9f; 0xa7; 0x83; 0x83; 0xf2; 0xb1; 0x34; 0xb6; 0xe4; 0xb7; 0xca; 0xb8;
0xc9; 0xb8; 0x0e; 0xbd; 0x7d; 0x0f; 0xc0; 0xf1; 0xd9; 0x03; 0xc5; 0x3a; 0xc6; 0xc7; 0xc8; 0xc9;
0xca; 0xcb; 0xcc; 0xcd; 0xce; 0xcf; 0xd0; 0xd1; 0xd2; 0xd3; 0xd4; 0xd5; 0xd6; 0xd7; 0xd8; 0xd9;
0xda; 0xdb; 0xa9; 0xcd; 0xdf; 0xdf; 0xe0; 0xe1; 0xe2; 0xe3; 0xe4; 0xe5; 0xe6; 0xe7; 0xe8; 0xe9;
0x26; 0xeb; 0xec; 0xed; 0xee; 0xef; 0xf0; 0xf1; 0xf2; 0xf3; 0xf4; 0xf5; 0xf6; 0xf7; 0xf8; 0xf9;
0x7d; 0x1f; 0x15; 0x60; 0x4d; 0x4d; 0x52; 0x7d; 0x0e; 0x27; 0x6d; 0x10; 0x6d; 0x5a; 0x06; 0x56;
0x47; 0x14; 0x42; 0x0e; 0xb6; 0xb2; 0xb2; 0xe6; 0xeb; 0xb4; 0x83; 0x8e; 0xd7; 0xe5; 0xd4; 0xd9;
0xc3; 0xf0; 0x80; 0x95; 0xf1; 0x82; 0x82; 0x9a; 0xbd; 0x95; 0xa4; 0x8d; 0x9a; 0x2b; 0x30; 0x69;
0x4a; 0x69; 0x65; 0x55; 0x1c; 0x7b; 0x69; 0x1c; 0x6e; 0x04; 0x74; 0x35; 0x21; 0x26; 0x2f; 0x60;
0x03; 0x4e; 0x37; 0x1e; 0x33; 0x54; 0x39; 0xe6; 0xba; 0xb4; 0xa2; 0xad; 0xa4; 0xc5; 0x95; 0xc8;
0xc1; 0xe4; 0x8a; 0xec; 0xe7; 0x92; 0x8b; 0xe8; 0x81; 0xf0; 0xad; 0x98; 0xa4; 0xd0; 0xc0; 0x8d;
0xac; 0x22; 0x52; 0x65; 0x7e; 0x27; 0x2b; 0x5a; 0x12; 0x61; 0x0a; 0x01; 0x7a; 0x6b; 0x1d; 0x67;
0x75; 0x70; 0x6c; 0x1b; 0x11; 0x25; 0x25; 0x70; 0x7f; 0x7e; 0x67; 0x63; 0x30; 0x3c; 0x6d; 0x6a;
0x01; 0x51; 0x59; 0x5f; 0x56; 0x13; 0x10; 0x43; 0x19; 0x18; 0xe5; 0xe0; 0xbe; 0xbf; 0xbd; 0xe9;
0xf0; 0xf1; 0xf9; 0xfa; 0xab; 0x8f; 0xc1; 0xdf; 0xcf; 0x8d; 0xf8; 0xe7; 0xe2; 0xe9; 0x93; 0x8e;
0xec; 0xf5; 0xc8; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x37; 0x7a; 0x07; 0x11; 0x1f; 0x1d; 0x68; 0x25; 0x32; 0x77; 0x1e; 0x62; 0x23; 0x5b; 0x47; 0x55;
0x53; 0x30; 0x11; 0x42; 0xf6; 0xf1; 0xb1; 0xe6; 0xc3; 0xcc; 0xf8; 0xc5; 0xe4; 0xcc; 0xc0; 0xd3;
0x85; 0xfd; 0x9a; 0xe3; 0xe6; 0x81; 0xb5; 0xbb; 0xd7; 0xcd; 0x87; 0xa3; 0xd3; 0x6b; 0x36; 0x6f;
0x6f; 0x66; 0x55; 0x30; 0x16; 0x45; 0x5e; 0x09; 0x74; 0x5c; 0x3f; 0x29; 0x2b; 0x66; 0x3d; 0x0d;
0x02; 0x30; 0x28; 0x35; 0x15; 0x09; 0x15; 0xdd; 0xec; 0xb8; 0xe2; 0xfb; 0xd8; 0xcb; 0xd8; 0xd1;
0x8b; 0xd5; 0x82; 0xd9; 0x9a; 0xf1; 0x92; 0xab; 0xe8; 0xa6; 0xd6; 0xd0; 0x8c; 0xaa; 0xd2; 0x94;
0xcf; 0x45; 0x46; 0x67; 0x20; 0x7d; 0x44; 0x14; 0x6b; 0x45; 0x6d; 0x54; 0x03; 0x17; 0x60; 0x62;
0x55; 0x5a; 0x4a; 0x66; 0x61; 0x11; 0x57; 0x68; 0x75; 0x05; 0x62; 0x36; 0x7d; 0x02; 0x10; 0x4b;
0x08; 0x22; 0x42; 0x32; 0xba; 0xe2; 0xb9; 0xe2; 0xd6; 0xb9; 0xff; 0xc3; 0xe9; 0x8a; 0x8f; 0xc1;
0x8f; 0xe1; 0xb8; 0xa4; 0x96; 0xf1; 0x8f; 0x81; 0xb1; 0x8d; 0x89; 0xcc; 0xd4; 0x78; 0x76; 0x61;
0x72; 0x3e; 0x37; 0x23; 0x56; 0x73; 0x71; 0x79; 0x63; 0x7c; 0x08; 0x11; 0x20; 0x69; 0x7a; 0x14;
0x68; 0x05; 0x21; 0x1e; 0x32; 0x27; 0x59; 0xb7; 0xcf; 0xab; 0xdd; 0xd5; 0xcc; 0x97; 0x93; 0xf2;
0xe7; 0xc0; 0xeb; 0xff; 0xe9; 0xa3; 0xbf; 0xa1; 0xab; 0x8b; 0xbb; 0x9e; 0x9e; 0x8c; 0xa0; 0xc1;
0x9b; 0x5a; 0x2f; 0x2f; 0x4e; 0x4e; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00;
0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00; 0x00|]
[<EntryPoint>]
let main args =
let arr = Array.concat (seq {yield mem; yield Array.zeroCreate (256*16-(mem |> Array.length))})
let vm = (Vm.WithMemory arr)
vm.cpu.reg Registers.DS <- 0x10
GCHQ.run_vm vm |> ignore
[448..498] |> List.iter (fun i -> System.Console.Write(sprintf "%c" (char vm.mem.memory.[i])))
printfn ""
0
@markusl
Copy link
Author

markusl commented Dec 17, 2011

When running the program, outputs all instructions to system debug output and finally dumps memory contents.

OpCodeMovr          cpu=[r0-r5: 0, 4, 0, 0, 0, 10, fl=0, ip=4]
OpCodeMovmMod0          cpu=[r0-r5: 0, 4, 0, aa, 0, 10, fl=0, ip=6]
...
OpCodeJmpeR1            cpu=[r0-r5: 1b, 8, 33, cb, 10, 1c, fl=0, ip=1a]
OpCodeJmpR1         cpu=[r0-r5: 1b, 8, 33, cb, 10, 1c, fl=0, ip=1a]
1�3ª@���Rr�s�²P0�À����2u1�32@���Rr�s�²Ã°0�À�ÿu��Ì}��`MMR}�'m�mZ�VG�B�¶²²æë´��×åÔÙÃð��ñ���½�¤��+0iJieU�{i�n�t5!&/`�N7�3T9溴¢­¤Å�ÈÁä�ìç��è�ð­�¤ÐÀ�¬"Re~'+Z�a
�zk�gGET /da75370fe15c4148bd4ceec861fbdaa5.exe HTTP/1.07z����h%2w�b#[GUS0�Böñ±æÃÌøÅäÌÀÓ
ý�ãæ�µ»×Í�£Ók6oofU0�E^  t\?)+f=
�0(5�   �Ýì¸âûØËØÑ�Õ�Ù�ñ�«è¦ÖÐ�ªÒ�ÏEFg }D�kEmT��`bUZJfa�Whu�b6}��K�"

For other implementations, see for example Dr Gareth Owen's PHP implementation at http://pastebin.com/6bWHKiEF

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment