Last active
September 28, 2015 20:17
-
-
Save markusl/1490780 to your computer and use it in GitHub Desktop.
GCHQ Challenge Stage 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When running the program, outputs all instructions to system debug output and finally dumps memory contents.
For other implementations, see for example Dr Gareth Owen's PHP implementation at http://pastebin.com/6bWHKiEF