X-NUCA 2018 summary

The seniors all participated in the offline competition, and they were too busy.
As a binary player, I did the reverse and pwn questions.
Thanks to the master for bring us this wonderful game, and I have learned a lot from this.

reverse

Code_Interpreter

It’s a simple VM program,I prefer using static analysis then write the parse.
Here is the parse code,But this program is not as good as I thought.
Plz masters put up with it,haha.

codes = [9, 4, 4, 9, 0, 0, 8, 1, 0, 8, 2, 1, 8, 3, 2, 6, 1, 4, 5, 1, 21, 7, 0, 1, 4, 0, 3, 1, 107, 204, 126, 29, 8, 1, 3, 4, 0, 1, 2, 10, 4, 0, 9, 0, 0, 8, 1, 0, 8, 2, 1, 8, 3, 2, 6, 3, 8, 5, 3, 3, 7, 0, 3, 3, 0, 2, 1, 124, 121, 121, 96, 8, 1, 3, 4, 0, 1, 2, 10, 4, 0, 9, 0, 0, 8, 1, 0, 8, 2, 1, 8, 3, 2, 6, 1, 8, 7, 0, 1, 3, 0, 2, 1, 189, 189, 188, 95, 8, 1, 3, 4, 0, 1, 2, 10, 4, 0, 0]
opcodes = {
    0:("EXIT",1),
    1:("SETMEM",5),
    2:("BACK",1),
    3:("ADD",3),
    4:("SUB",3),
    5:("MUL",3),
    6:("SHR",3),
    7:("MOV",3),
    8:("MOVFLAG",3),
    9:("XOR",3),
    10:("OR",3)
}
ip = 0
memip = 0
while codes[ip] != 0:
    opcode = opcodes[codes[ip]]
    print("%03x: "%ip+opcode[0],end="")
    if opcode[0] == "MOVFLAG":
        print("  "+"REG"+str(codes[ip+1])+"  "+"FLAG"+str(codes[ip+2]),end="")
    elif opcode[1] == 3:
        print("  "+"REG"+str(codes[ip+1])+"  "+"REG"+str(codes[ip+2]),end="")
    elif opcode[1] == 5:
        print(str(memip)+"  "+str(codes[ip+1])+"  "+str(codes[ip+2])+"  "+str(codes[ip+3])+"  "+str(codes[ip+4]),end="")
        print("  #"+str(codes[ip+1]+(codes[ip+2]<<8)+(codes[ip+3]<<16)+(codes[ip+4]<<24)),end="")
        memip += 1
    elif opcode[0] == "BACK":
        memip -= 1
    print()
    ip += opcode[1]

Here is the asm code.

000: XOR  REG4  REG4

003: XOR  REG0  REG0
006: MOVFLAG  REG1  FLAG0
009: MOVFLAG  REG2  FLAG1
00c: MOVFLAG  REG3  FLAG2
00f: SHR  REG1  4
012: MUL  REG1  21
015: MOV  REG0  REG1
018: SUB  REG0  REG3
01b: SETMEM0  107  204  126  29  #494849131
020: MOVFLAG  REG1  FLAG3
023: SUB  REG0  REG1
026: BACK
027: OR  REG4  REG0

02a: XOR  REG0  REG0
02d: MOVFLAG  REG1  FLAG0
030: MOVFLAG  REG2  FLAG1
033: MOVFLAG  REG3  FLAG2
036: SHR  REG3  8
039: MUL  REG3  3
03c: MOV  REG0  REG3
03f: ADD  REG0  REG2
042: SETMEM0  124  121  121  96  #1618573692
047: MOVFLAG  REG1  FLAG3
04a: SUB  REG0  REG1
04d: BACK
04e: OR  REG4  REG0

051: XOR  REG0  REG0
054: MOVFLAG  REG1  FLAG0
057: MOVFLAG  REG2  FLAG1
05a: MOVFLAG  REG3  FLAG2
05d: SHR  REG1  8
060: MOV  REG0  REG1
063: ADD  REG0  REG2
066: SETMEM0  189  189  188  95  #1606204861
06b: MOVFLAG  REG1  FLAG3
06e: SUB  REG0  REG1
071: BACK
072: OR  REG4  REG0

Only when REG4 equal 0 then we can get flag,and every round REG4 OR REG0,so we need make sure REG0 equal 0.
I use z3 solve this problem.

from z3 import *
f1 = BitVec("f1",32)
f2 = BitVec("f2",32)
f3 = BitVec("f3",32)

s = Solver()
s.add((f1>>4)*21-f3-494849131==0)
s.add((f3>>8)*3+f2-1618573692==0)
s.add((f1>>8)+f2-1606204861==0)
s.add(f1&0xFF==0x5E)
s.add(f3&0xFF==0x5E)
s.add(f2&0xFF0000==0x5E0000)

if s.check()==sat:
    m = s.model()
    print("X-NUCA{"+hex(m[f1].as_long())[2:]+hex(m[f2].as_long())[2:]+hex(m[f3].as_long())[2:]+"}")

Unfinished…