CRACK Solution

Tiny Machine

CRACK bytecode VM (opcode dispatch)

In-game screenshot of Tiny Machine
In-game view
FamilyCRACK Graph0.897 DifficultyHard Ring05 IDz2_vm_dispatch
Accepted input VMACHN3
Techniquebytecode VM (opcode dispatch) Rulenonzero SampleVMACHN3

Walkthrough

Recover the accepted input below, then submit it to the CRACK verifier.

Reject Samples

  • VMACHN4
  • vmachn3
  • VMACHN
  • VMACHN33
  • BYTECOD
Verifier Listing
; z2_vm_dispatch: a miniature bytecode VM. A short program of (opcode,operand)
; pairs is dispatched per input character to transform it, and the transformed
; byte is compared at each position. The program is
;   { 1,0x5A,  2,0x11,  3,0x03,  1,0x0F,  0 }
; with opcodes  1 = XOR operand,  2 = ADD operand,  3 = ROL by operand,  0 = stop.
; So each byte becomes  acc = rol8((acc XOR 0x5A) + 0x11, 3) XOR 0x0F.  Length is
; 7; the targets are 0xE7 0x4E 0x6E 0x5E 0x16 0x26 0xDC. Inverting the program in
; reverse per byte recovers VMACHN3. r0 = 1 on accept; rule: nonzero.
;
; FAITHFUL to the original: this keeps the real fetch-decode-dispatch loop (the
; bytecode lives in SCRATCH; an inner loop reads opcode/operand pairs and
; branches on the opcode), rather than inlining the four operations. The 8-bit
; core runs the same VM the ARM64 version did; the only adaptation is that the
; program array lives in SCRATCH instead of on a stack (there is no stack).

        len   r2
        cmp   r2, 7
        jnz   bad

        ; --- lay the bytecode program into scratch[0..8] ------------------
        mov   r1, 0
        mov   r0, 1
        stb   [r1], r0      ; [0] op XOR
        inc   r1
        mov   r0, 0x5A
        stb   [r1], r0      ; [1] operand
        inc   r1
        mov   r0, 2
        stb   [r1], r0      ; [2] op ADD
        inc   r1
        mov   r0, 0x11
        stb   [r1], r0      ; [3] operand
        inc   r1
        mov   r0, 3
        stb   [r1], r0      ; [4] op ROL
        inc   r1
        mov   r0, 0x03
        stb   [r1], r0      ; [5] operand
        inc   r1
        mov   r0, 1
        stb   [r1], r0      ; [6] op XOR
        inc   r1
        mov   r0, 0x0F
        stb   [r1], r0      ; [7] operand
        inc   r1
        mov   r0, 0
        stb   [r1], r0      ; [8] op STOP

        ; --- outer loop over the 7 input characters ----------------------
        mov   r7, 0         ; r7 = input index
outer:  cmp   r7, 7
        jge   ok
        ldb   r3, [r7]      ; r3 = acc, the working byte

        ; --- inner fetch-decode-dispatch loop ----------------------------
        mov   r6, 0         ; r6 = program counter into scratch
vmloop: lds   r4, [r6]      ; r4 = opcode
        cmp   r4, 0
        jz    vmdone        ; opcode 0 -> stop
        mov   r5, r6
        inc   r5
        lds   r5, [r5]      ; r5 = operand (scratch[pc+1])

        cmp   r4, 1
        jz    op_xor
        cmp   r4, 2
        jz    op_add
        cmp   r4, 3
        jz    op_rol
        jmp   vmadv         ; unknown opcode: no-op
op_xor: xor   r3, r5
        jmp   vmadv
op_add: add   r3, r5
        jmp   vmadv
op_rol: rol   r3, r5
vmadv:  add   r6, 2         ; advance to the next pair
        jmp   vmloop

vmdone: ; --- compare acc against this position's target ------------------
        cmp   r7, 0
        jz    t0
        cmp   r7, 1
        jz    t1
        cmp   r7, 2
        jz    t2
        cmp   r7, 3
        jz    t3
        cmp   r7, 4
        jz    t4
        cmp   r7, 5
        jz    t5
        mov   r1, 0xDC      ; position 6
        jmp   chk
t0:     mov   r1, 0xE7
        jmp   chk
t1:     mov   r1, 0x4E
        jmp   chk
t2:     mov   r1, 0x6E
        jmp   chk
t3:     mov   r1, 0x5E
        jmp   chk
t4:     mov   r1, 0x16
        jmp   chk
t5:     mov   r1, 0x26
chk:    cmp   r3, r1
        jnz   bad
        inc   r7
        jmp   outer

ok:     mov   r0, 1
        ret
bad:    mov   r0, 0
        ret