Created
February 14, 2014 20:41
-
-
Save rtt/9008829 to your computer and use it in GitHub Desktop.
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
//-------------------------------------------------------------------------------------------------- | |
// | |
// stage 2 of 3 | |
// | |
// challenge: | |
// reveal the solution within VM.mem | |
// | |
// disclaimer: | |
// tested in ie 9, firefox 6, chrome 14 and v8 shell (http://code.google.com/apis/v8/build.html), | |
// other javascript implementations may or may not work. | |
// | |
//-------------------------------------------------------------------------------------------------- | |
var VM = { | |
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 | |
], | |
s_seg: 2, // segment size | |
cpu: { | |
ip: 0x00, // instruction pointer | |
r0: 0x00, | |
r1: 0x00, | |
r2: 0x00, | |
r3: 0x00, | |
cs: 0x00, | |
ds: 0x10, | |
fl: 0x00, | |
firmware: [0xd2ab1f05, 0xda13f110], | |
is_halted: false | |
}, | |
exec: function() | |
{ | |
// virtual machine architecture | |
// ++++++++++++++++++++++++++++ | |
// | |
// segmented memory model with 16-byte segment size (notation seg:offset) | |
// | |
// 4 general-purpose registers (r0-r3) | |
// 2 segment registers (cs, ds equiv. to r4, r5) | |
// 1 flags register (fl) | |
// | |
// 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) | |
// | |
// instruction set | |
// +++++++++++++++ | |
// | |
// Notes: | |
// * r1, r2 => operand 1 is register 1, operand 2 is register 2 | |
// * movr r1, r2 => move contents of register r2 into register r1 | |
// | |
// 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 | |
// | |
// flags | |
// +++++ | |
// | |
// cmp r1, r2 instruction results in: | |
// r1 == r2 => fl = 0 | |
// r1 < r2 => fl = 0xff | |
// r1 > r2 => fl = 1 | |
// | |
// jmpe r1 | |
// => if (fl == 0) jmp r1 | |
// else nop | |
while (!this.cpu.is_halted) { | |
this.cpu.ip = this.dispatch(this.mem.slice(this.cpu.ip, this.cpu.ip+2)) | |
} | |
}, | |
dispatch: function(segment) { | |
advance = 0; | |
ins = this.instruction_set[this.get_opcode(segment[0])];; | |
mod = this.get_mod(segment[0]); | |
// print some nice info | |
this.dump(); | |
print('=>', | |
('0x0' + ins.code), | |
ins.name, | |
'([', ('0x' + segment[0].toString(16)), ',', | |
('0x' + segment[1].toString(16)), | |
'])'); | |
// execute the instruction and add | |
// its return value to the cpu's internal | |
// pointer | |
this.cpu.ip += ins.op((segment.length == 2 ? segment : segment[0]), mod, this) | |
this.dump(); | |
print("\n"); | |
// return the cpu's current pointer | |
return this.cpu.ip | |
}, | |
dump: function() { | |
print('ip:', this.cpu.ip, | |
', r0:', this.cpu.r0, | |
', r1:', this.cpu.r1, | |
', r2:', this.cpu.r2, | |
', r3:', this.cpu.r3, | |
', ds:', this.cpu.ds, | |
', cs:', this.cpu.cs, | |
', fl:', this.cpu.fl); | |
}, | |
addr: function(segment_index, offset) { | |
// 16-byte segments + any offset given | |
return (this.cpu[segment_index] * 16) + offset; | |
}, | |
instruction_set: [ | |
{ | |
'code': 0x00, | |
'name': 'jmp', | |
'op': function(ins, mod, inst) { | |
print(' (ip)', inst.cpu.ip, ':', this.name, mod); | |
op1 = inst.get_register(inst.get_opand1(ins[0])); | |
if (!mod) { | |
addr = inst.addr('cs', inst.cpu[op1]); | |
print(' (!mod)', op1, addr, inst.cpu[op1]); | |
inst.cpu.ip = addr; | |
} | |
else { | |
op2 = ins[1]; | |
print(' (mod)', op2, ':', op1); | |
addr = op2 * 0x10 + inst.cpu[op1]; | |
inst.cpu.cs = op2; | |
inst.cpu.ip = addr; | |
} | |
return 0; | |
}, | |
}, | |
{ | |
'code': 0x01, | |
'name': 'movr', | |
'op': function(ins, mod, inst) { | |
op1 = inst.get_register(inst.get_opand1(ins[0])); | |
if (!mod) { | |
// take value from op2 | |
op2 = inst.get_register(ins[1]); | |
print(' (!mod) (ip)', inst.cpu.ip, ':', this.name, op2, ',', this.cpu[op2]); | |
inst.cpu[op1] = inst.cpu[op2] | |
} | |
else { | |
// take immediate value | |
print(' (mod) (ip)', inst.cpu.ip, ':', this.name, op1, ',', ins[1]); | |
inst.cpu[op1] = ins[1]; | |
print(' ', op1, '=', inst.cpu[op1]); | |
} | |
return inst.s_seg; // advance ip by two | |
} | |
}, | |
{ | |
'code': 0x02, | |
'name': 'movm', | |
'op': function(ins, mod, inst) { | |
op1 = inst.get_register(inst.get_opand1(ins[0])); | |
op2 = inst.get_register(ins[1]); | |
print(' (ip)', inst.cpu.ip, ':', this.name, mod, op1, op2); | |
if (!mod) { | |
addr = inst.addr('ds', inst.cpu[op2]); | |
print(' (!mod)', op1, ',', '[ds:', op2, ']', addr, inst.mem[addr]); | |
inst.cpu[op1] = inst.mem[addr]; | |
print(' ', op1, '=', inst.cpu[op1]); | |
} | |
else { | |
addr = inst.addr('ds', inst.cpu[op1]); | |
print(' (mod)', '[ds:', op1, '],', op2, addr, inst.mem[addr]); | |
inst.mem[addr] = inst.cpu[op2] | |
print(' mem:', addr, '=', inst.mem[addr]); | |
} | |
return inst.s_seg; // done, advance by two | |
} | |
}, | |
{ | |
'code': 0x03, | |
'name': 'add', | |
'op': function(ins, mod, inst) { | |
op1 = inst.get_register(inst.get_opand1(ins[0])); | |
print(' (ip)', inst.cpu.ip, ':', this.name, op1, mod); | |
// & 0xff to ensure val no larger than 1 byte | |
if (!mod) { | |
print(' (!mod)', op1, op2, inst.cpu[op1], inst.cpu[op2]); | |
op2 = inst.get_register(ins[1]); | |
// add both registers together | |
inst.cpu[op1] = (inst.cpu[op1] + inst.cpu[op2]) & 0xff; | |
print(' ', op1, inst.cpu[op1]); | |
} | |
else { | |
print(' (mod)', ins[1], op2, ',', inst.cpu[op1]); | |
// add the value in ins[1] | |
inst.cpu[op1] = (inst.cpu[op1] + ins[1]) & 0xff; | |
print(' ', op1, '=', inst.cpu[op1]); | |
} | |
return inst.s_seg; | |
} | |
}, | |
{ | |
'code': 0x04, | |
'name': 'xor', | |
'op': function(ins, mod, inst) { | |
op1 = inst.get_register(inst.get_opand1(ins[0])); | |
print(' (ip)', inst.cpu.ip, ':', this.name, mod, ',', op1); | |
if (!mod) { | |
op2 = inst.get_register(ins[1]); | |
print(' (!mod)', op1, op2, inst.cpu[op1], inst.cpu[op2]); | |
inst.cpu[op1] = inst.cpu[op1] ^ inst.cpu[op2]; | |
print(' ', op1, '=', inst.cpu[op1]); | |
} | |
else { | |
print(' (mod)', ins[1]); | |
inst.cpu[op1] = (inst.cpu[op1] ^ ins[1]); | |
} | |
return inst.s_seg; | |
}, | |
}, | |
{ | |
'code': 0x05, | |
'name': 'cmp', | |
'op': function(ins, mod, inst) { | |
op1_register = inst.get_register(inst.get_opand1(ins[0])); | |
op1 = inst.cpu[op1_register]; | |
print(' ', inst.cpu.ip, ':', this.name, mod, op1_register, ','); | |
op2 = '' | |
if (!mod) { | |
op2_regiser = inst.get_register(ins[1]); | |
print(' (!mod)', op2_register); | |
op2 = inst.cpu[op2_register]; | |
} | |
else { | |
op2 = ins[1]; | |
print(' (mod)', op2); | |
} | |
d = op1 - op2; | |
if (d == 0) { | |
inst.cpu.fl = 0; | |
} | |
else if (d > 0) { | |
inst.cpu.fl = 1; | |
} | |
else { | |
inst.cpu.fl = -1; | |
} | |
print(' cpu.fl =', inst.cpu.fl); | |
return inst.s_seg; | |
} | |
}, | |
{ | |
'code': 0x06, | |
'name': 'jmpe', | |
'op': function(ins, mod, inst) { | |
print(' (ip)', inst.cpu.ip, mod); | |
if (inst.cpu.fl == 0) { | |
return inst.instruction_set[0].op(ins, mod, ins); | |
} | |
print(' [!] Not taken'); | |
return mod+1; | |
} | |
}, | |
{ | |
'code': 0x07, | |
'name': 'hlt', | |
'op': function(ins, mod, inst) { | |
inst.cpu.is_halted = true; | |
print('hlt') | |
print('[!] Halting.'); | |
return 0; | |
} | |
} | |
], | |
get_register: function(ins) { | |
// return a register to use for each opcode. | |
// note halt (HLT) has no register | |
return ['r0', 'r1', 'r2', 'r3', 'cs', 'ds'][ins]; | |
}, | |
get_opcode: function(w) { | |
// shift bits 5 to the right to get the value of the 3 leftmost bits | |
return (w >> 5) & 0xff; | |
}, | |
get_mod: function(w) { | |
// filter by 0x0f to figure out | |
return (w >> 4) & 0x01; | |
}, | |
get_opand1: function(w) { | |
// filter for 4 rightmost bits | |
return w & ((1 << 4) - 1); | |
}, | |
get_opand2: function(w) { | |
// pass-thru | |
return w; | |
}, | |
}; | |
//-------------------------------------------------------------------------------------------------- | |
try | |
{ | |
VM.exec(); | |
} | |
catch(e) | |
{ | |
print(e); | |
} | |
//-------------------------------------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment