[zer0pts CTF 2020] vmlog

I wrote my vm and its program. Can you guess the source code and input?

解説

vm上で動かされたプログラムは、Brainfuckの仕様を拡張したもので書かれていたようです
そのプログラムをよく見ると1文字の入力につき1回メモリをダンプしていることが分かります
また、ログの行数から入力された文字数は34文字だと分かります

これらのことから

  1. 現在の状態を保存
  2. 1文字入力
  3. 入力した文字でメモリダンプが起こるまで処理
  4. メモリダンプがログと一致していれば入力した文字を保存、そうでなければ入力前に保存しておいた状態を読み込んで別の文字で試行

の手順を34回実行すれば入力が逆算できます

#!/usr/bin/env python
import sys

program = "M+s+>s>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[s<<l>*<s>>l-]<<l-s>l*-s*-s*-s*-s*-s*-s>l*+++++s*-----s****s>>l+s[Ml-s<<l>,[<<*>>s<<<l>>>%<s>>l<s>l+s<l]>l]<<lp"
o_reg = 0  # 
o_mem = [0 for _ in range(10)]
o_p = 0    #pointer
o_pc = 0   #program counter
o_buf = "" #buffer when use print func(p)

correct = open('log.txt', 'r').readlines()

def run(num, c):
    global o_reg
    global o_mem
    global o_p
    global o_pc
    global o_buf

    reg = o_reg
    mem = o_mem[0:]
    p = o_p
    pc = o_pc
    buf = o_buf[0:]

    #print(program)

    while pc < len(program):
        op = program[pc]

        # increment
        if op == "+":
            reg += 1
        # decrement
        elif op == "-":
            reg -= 1
        # multiplex
        elif op == "*":
            reg *= mem[p]
        # mod
        elif op == "%":
            reg = mem[p] % reg
        # load
        elif op == "l":
            reg = mem[p]
        # set
        elif op == "s":
            mem[p] = reg
        # increment pointer
        elif op == ">":
            p = (p + 1) % 10
        # decrement pointer
        elif op == "<":
            p = (p - 1) % 10
        # getchar
        elif op == ",":
            #a = sys.stdin.buffer.read(1)
            a = c
            if not a:
                reg = 0
            else:
                reg += ord(a)
        # print
        elif op == "p":
            buf += str(reg)
        # loop begin
        elif op == "[":
            if reg == 0:
                cnt = 1
                while cnt != 0:
                    pc += 1
                    if program[pc] == "[":
                        cnt += 1
                    if program[pc] == "]":
                        cnt -= 1
        # loop end
        elif op == "]":
            if reg != 0:
                cnt = 1
                while cnt != 0:
                    pc -= 1
                    if program[pc] == "[":
                        cnt -= 1
                    if program[pc] == "]":
                        cnt += 1
        # print memory
        elif op == "M":
            pc += 1
            #print(mem)
            if mem == eval(correct[num]):
                o_reg = reg
                o_mem = mem[0:]
                o_p = p
                o_pc = pc
                o_buf = buf[0:]
                return True
            else:
                return False

        pc += 1

    print(buf)

def sol():
    flag = []
    while len(flag) != 34:
        for c in range(0x21, 0x7f):
            if run(len(flag) + 1, chr(c)):
                flag.append(chr(c))
                break;
    print(''.join(flag))

sol()

zer0pts{3asy_t0_f0110w_th3_l0g?}