Sunday, 11 December 2011

Beating the GCHQ challenge (part 3)

This final stage of the challenge is a windows-only affair. You get an executable file without much else.

*This challenge is a straight cracking/reverse-engineering exercise. I will not detail how I do this, but I will detail the puzzle that exists in the code.

Running the executable (in a safe, disposable virtual machine of course!) reveals that the executable needs an extra dll. A quick Google search reveals that this is the crypt module of cygwin, so I installed the correct libraries and tried again:


Entering the hostname of the challenge website at least told me that the program also wanted a licence file. From there I dived into the code and found the following:

  • A rather interesting string - "hqDTK7b8K2rvw".
  • Code that searches for a file named "licence.txt", sets aside 24 bytes of zeroed memory and then uses this memory to load the contents of the file.
  • The first 4 bytes of this data are checked against a hard coded value - 0x67636871. This is "gchq" in ascii. So far so good!
  • The next 20 bytes are then passed to the unix "crypt" function with the mystery string ("hqDTK7b8K2rvw") as a salt. The return is again checked against the mystery string and if its the same, the code continues.
  • At this point, the final 12 bytes of the licence are loaded onto the stack and the code branches to a new procedure.
  • This new procedure tries to contact the hostname you specified on port 80 and perform a HTTP  GET request. The URL used for this is interesting: "GET /%s/%x/%x/%x/key.txt HTTP/1.0\r\n\r\n". For the first string in this format specifier, the program passes the mystery string ("hqDTK7b8K2rvw"). The other 3 hex values are the 12 bytes read at the end of the licence.
Here's where it gets interesting. Looking at the crypt man-page, the function discards all but the first 8 bytes of the password and all but the first 2 bytes of the salt. The salt then becomes the first 2 bytes of the encrypted password (that is how the salt and encrypted password can be compared to see if the correct password is given). 

So I need to find a 20 byte password. How about "canyoucrackit.co.uk" a NULL char at the end? Nope. That didn't work :(



I realised that if I tried a brute force attack on this encrypted string it would take ages.  Also, as all but the first 8 chars are discarded, the final 12 bytes would not be revealed by the attack, and this was the information I needed. At this point I was stuck.

Then I remembered the weird information from the other 2 stages:

  • The jumped DWORD in stage 1 - 0xa3bfc2af
  • The firmware values from stage 2 - 0xd2ab1f05, 0xda13f110
Now, trying these values in the URL gives me www.canyoucrackit.co.uk/hqDTK7b8K2rvw/a3bfc2af/d2ab1f05/da13f110/key.txt

Go to that page and instead of a 404 page asking you to try again you get the following text: "Pr0t3ct!on#cyber_security@12*12.2011+". Put this into the form on http://www.canyoucrackit.co.uk/ and you get through to this:





You get a chance to apply for:
  • Cyber Security Specialist - GC10 (£25,446)
  • Senior Cyber Security Specialist - GC9 (£31,152)
And that's that for this year, unless there more in that final block of memory on stage 2!


Friday, 9 December 2011

Beating the GCHQ challenge (part 2)

So after the let-down of having to complete another test after the last one, I found myself with the following javascript file:



//--------------------------------------------------------------------------------------------------
//
// 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 = {
 
    cpu: {
        ip: 0x00,
   
        r0: 0x00,
        r1: 0x00,
        r2: 0x00,
        r3: 0x00,
   
        cs: 0x00,
        ds: 0x10,
   
        fl: 0x00,
   
        firmware: [0xd2ab1f05, 0xda13f110]
    },
 
    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
    ],
 
    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
   
        throw "VM.exec not yet implemented";
    }
 
};


//--------------------------------------------------------------------------------------------------


try
{
    VM.exec();
}
catch(e)
{
    alert('\nError: ' + e + '\n');
}


//--------------------------------------------------------------------------------------------------
 


So we have the details of an instruction set, three segments of memory and some variables that represent registers (oh...and some suspicious looking firmware values!).

The task here is to write a simple disassembler, be able to store a set of decoded instructions and to then execute them as part of a virtual machine. The tricky part is that the first section of code decodes the next one, so you must disassemble, build the instructions, run, disassemble, build more instructions then run again. After this you find the following in the second segment of memory:

'G' , 'E' , 'T' , ' ' , '/' , 'd' , 'a' , '7' , '5' , '3' , '7' , '0' , 'f' , 'e' , '1' , '5' ,
'c' , '4' , '1' , '4' , '8' , 'b' , 'd' , '4' , 'c' , 'e' , 'e' , 'c' , '8' , '6' , '1' , 'f' ,
'b' , 'd' , 'a' , 'a' , '5' , '.' , 'e' , 'x' , 'e' , ' ' , 'H' , 'T' , 'T' , 'P' , '/' , '1' ,

This is the address for the next stage of the challenge.

Interestingly, the third segment seems unchanged - very suspicious as there's not much spare information in any of these challenges.

My final code for this stage:



//--------------------------------------------------------------------------------------------------
//
// 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 = {  
        cpu: {
        ip: 0x00,
       
        r0: 0x00,
        r1: 0x00,
        r2: 0x00,
        r3: 0x00,
       
        cs: 0x00,
        ds: 0x10,
     
        fl: 0x00,
     
        firmware: [0xd2ab1f05, 0xda13f110]
    },
   
    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
    ],


    decoded_instructions: {},


    decode_mem: function()
    {
        var pos = this.decode_pos;
        var b1 = this.mem[(this.decode_offset * 16) + this.decode_pos];
        var b2 = this.mem[(this.decode_offset * 16) + this.decode_pos + 1];
        var operand2 = b2;
        var mod = ((0x10 & b1) >> 4);
        var operand1 = (0x07 & b1);
        var instruction = ((0xE0 & b1) >> 5);
        if(instruction == 0x07){ //hlt
            this.decoded_instructions[pos] = ["htl"];
            return false;
        }
        if(mod == 0){
            switch(instruction){
            case 0x00: //"jmp"
                this.decode_pos += 1;
                this.decoded_instructions[pos] = ["jmp", "r" + String(operand1)];
                return true;
            case 0x01: //"movr"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["movr", "r" + String(operand1), "r" +
                                                     String(operand2)]);
                return true;
            case 0x02: //"movm"
                this.decode_pos += 2;  
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["movm", "r" + String(operand1), "ds:r" +
                                                     String(operand2)]);
                return true;
            case 0x03: //"add"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["add", "r" + String(operand1), "r" +
                                                     String(operand2)]);
                return true;
            case 0x04: //"xor"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["xor", "r" + String(operand1), "r" +
                                                     String(operand2)]);
                return true;
            case 0x05: //"cmp"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["cmp", "r" + String(operand1), "r" +
                                                     String(operand2)]);
                return true;
            case 0x06: //"jmpe"
                this.decode_pos += 1;
                this.decoded_instructions[pos] = ["jmpe", "r" + String(operand1)];
                return true;
            }
            } else { //mod == 1
            switch(instruction){
            case 0x00: //"jmp"
                this.decode_pos += 2;
                this.decode_offset = operand2 * 16;
                this.decoded_instructions[pos] = ["jmp", "s" + String(operand2) + ":r" +
                                                  String(operand1)];
                return false;
            case 0x01: //"movr"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["movr", "r" + String(operand1), operand2]);
                return true;
            case 0x02: //"movm"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["movm", "ds:r" + String(operand1), "r" +
                                                     String(operand2)]);
                return true;
            case 0x03: //"add"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["add", "r" + String(operand1), operand2]);
                return true;
            case 0x04: //"xor"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["xor", "r" + String(operand1), operand2]);
                return true;
            case 0x05: //"cmp"
                this.decode_pos += 2;
                this.decoded_instructions[pos] =
                    this.swap_out_segment_registers(["cmp", "r" + String(operand1), operand2]);
                return true;
            case 0x06: //"jmpe"
                this.decode_pos += 2;
                this.decode_offset = operand2 * 16;
                this.decoded_instructions[pos] = ["jmpe", "s" + String(operand2) + ":r" +
                                                  String(operand1)];
                return false;
            }
        }
    },
    run_instructions: function(){
        document.write("<table border=\"1\">");
        var looping = true;
        while(looping && this.cpu.ip < 256){
            if(!(this.cpu.ip in this.decoded_instructions)){
                this.cpu.ip++;
                continue;
            }
            var instruction = this.decoded_instructions[this.cpu.ip];
            switch(instruction[0]){
            case "jmp":
                if(instruction[1][0] == "s"){
                    var re = /s(\d*):(r\d)/;
                    var vals = instruction[1].match(re);
                    this.cpu.cs = Number(vals[1]);
                    this.cpu.ip = eval("this.cpu." + vals[2]) - 1;
                    looping = false;
                } else {
                    this.cpu.ip = eval("this.cpu." + instruction[1]) - 1;
                }
                break;
            case "jmpe":
                if(this.cpu.fl != 0){
                    break;
                }
                if(instruction[1][0] == "s"){
                    var re = /s(\d*):(r\d)/;
                    var vals = instruction[1].match(re);
                    this.cpu.cs = Number(vals[1]);
                    this.cpu.ip = eval("this.cpu." + vals[2]) - 1;
                    looping = false;
                } else {
                    this.cpu.ip = eval("this.cpu." + instruction[1]) - 1;
                }
                break;
            case "movr":
                if(instruction[2][0] == "r" || instruction[2][0] == "c" ||
                        instruction[2][0] == "d"){
                    eval("this.cpu." + instruction[1] + " = this.cpu." + instruction[2])
                } else {
                    eval("this.cpu." + instruction[1] + " = " + instruction[2]);
                }
                break;
            case "movm":
                var re = /ds:(r\d*)/;
                if(instruction[1][0] == "d"){ //mod 1
                    var vals = instruction[1].match(re);
                    var r = eval("this.cpu." + vals[1]);
                    this.mem[r + (this.cpu.ds * 16)] = eval("this.cpu." + instruction[2]);
                } else {
                    var vals = instruction[2].match(re);
                    var r = eval("this.cpu." + vals[1]);
                    eval("this.cpu." + instruction[1] + " = this.mem[r + " +
                         (this.cpu.ds * 16) + "]");
                }
                break;
            case "add":
                if(instruction[2][0] == "r" || instruction[2][0] == "c" ||
                        instruction[2][0] == "d"){
                    eval("this.cpu." + instruction[1] + " += this.cpu." + instruction[2]);
                } else {
                    eval("this.cpu." + instruction[1] + " += " + instruction[2]);
                }  
                break;
            case "xor":
                if(instruction[2][0] == "r"){
                    eval("this.cpu." + instruction[1] + " ^= this.cpu." + instruction[2]);
                } else {
                    eval("this.cpu." + instruction[1] + " ^= " + instruction[2]);
                }  
                break;
            case "cmp":
                if(instruction[2][0] == "r"){
                    if(eval("this.cpu." + instruction[1]) == eval("this.cpu." + instruction[2])){
                 this.cpu.fl = 0;
                    } else if(eval("this.cpu." + instruction[1]) > eval("this.cpu." +
                                                                        instruction[2])){
                 this.cpu.fl = 1;
                    } else{
                 this.cpu.fl = 0xFF;
                    }
                } else {
                    if(eval("this.cpu." + instruction[1]) == instruction[2]){
                 this.cpu.fl = 0;
                    } else if(eval("this.cpu." + instruction[1]) > instruction[2]){
                 this.cpu.fl = 1;
                    } else{
                 this.cpu.fl = 0xFF;
                    }
                }
                break;
            case "hlt":
                looping = false;
                break;         
            }
            this.cpu.ip++;
            document.write("<tr>");
            document.write("<td>" + this.get_instruction_text(instruction));
            document.write("</td><td>" + this.get_state() + "</td></tr>");
        }
        document.write("</table></p>");
        this.decoded_instructions = {}
        this.decode_offset = this.cpu.cs;
        this.decode_pos = 0;
    },
    swap_out_segment_registers: function(instruction){
        for(var i = 0; i < instruction.length;i++){
            if(instruction[i] == "r4"){instruction[i] = "cs";}
            if(instruction[i] == "r5"){instruction[i] = "ds";}
        }
        return instruction;
   },
    print_mem: function(){
        document.write("Memory Dump<br />");
        for(var i = 0; i < this.mem.length; i++){
            if(this.mem[i] < 0x20 || this.mem[i] > 0x7E){
                var v = this.mem[i].toString(16);
                if(v.length == 1){
                    v = "0x0" + v;
                } else {
                    v = "0x" + v;
                }
                document.write(v + ", ");
            } else {
                document.write("'" + String.fromCharCode(this.mem[i]) + "' , ");
            }
            if(((i + 1) % 16) == 0){
                document.write("<br />");
            }
            if(((i + 1) % 256) == 0){
                document.write("<br />");
            }
        }
    },
    get_state: function(){
        var state = "ip = " + this.cpu.ip + ", ";
        state += "cs = " + this.cpu.cs + ", ";
        state += "ds = " + this.cpu.ds + ", ";
        state += "r0 = " + this.cpu.r0 + ", ";
        state += "r1 = " + this.cpu.r1 + ", ";
        state += "r2 = " + this.cpu.r2 + ", ";
        state += "r3 = " + this.cpu.r3 + ", ";
        state += "fl = " + this.cpu.fl + ".";
        return state;
    },
    get_instruction_text: function(instruction){
        var text = instruction[0];
        if(instruction.length == 2){
            text += " " + instruction[1];
        }
        if(instruction.length == 3){
            text += " " + instruction[1] + ", " + String(instruction[2]);
        }
        return text;
    },
    print_instructions: function(){
        document.write("<p>");
        document.write("Decoded instructions:<br />");
        document.write("<table border=\"1\">");
   
        for(var i = 0; i < 256 ; i++){
            if(!(i in this.decoded_instructions)){
                continue;
            }
            document.write("<tr>");
            var instruction = this.decoded_instructions[i];
            document.write("<td>At pos " + i + "</td>");
            document.write("<td>" + this.get_instruction_text(instruction));
            document.write("</td><td>");
        }
        document.write("</table></p>");
    },
    decode_pos : 0x00,
    decode_offset: 0x00,
    decode: function(){
        while(this.decode_mem()){ }
        this.print_instructions()
        this.run_instructions()
        this.print_mem()
        while(this.decode_mem()){ }
        this.print_instructions()
        this.run_instructions()
        this.print_mem()
/*
        this.decode_offset = 22;
        this.decode_pos = 0;
        while(this.decode_mem()){ }
        this.print_instructions()
        this.print_mem()
*/

    },
    instructions: ["jmp", "movr","movm", "add","xor","cmp","jmpe", "hlt"],
    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
 //    throw "VM.exec not yet implemented";
    }
 
};


//--------------------------------------------------------------------------------------------------


try
{
    VM.decode();
//    VM.exec();
}
catch(e)
{
    alert('\nError: ' + e + '\n');
}

//--------------------------------------------------------------------------------------------------
 

Use the following html file and load it in Chrome or Firefox to see it work:

<html>
    <head>
        <script type="text/javascript" src="stage2.js">
        </script>
    </head>
    <body>
    </body>
</html>


Now onto stage 3...