[zer0pts CTF 2020] QR Puzzle

This puzzle is a puzzling puzzle.

解説

main関数はこんなかんじ

ulong main(int argc,char **argv)
{
  long *plVar1;
  int *keys;
  long in_FS_OFFSET;
  int local_24;
  long local_20;

  local_20 = *(long *)(in_FS_OFFSET + 0x28);
  if (argc < 4) {
    __printf_chk(1,"Usage: %s [qr] [key] [output]\n",*argv);
  }
  else {
    puts("[+] Loading QR...");
    plVar1 = (long *)LoadQr(&local_24,argv[1]); // fun_400980
    puts("[+] Done!");
    puts("[+] Loading key...");
    keys = LoadKey(argv[2]);    // fun_400af0
    puts("[+] Done!");
    puts("[+] Encrypting...");
    Encrypt((long)plVar1,keys); // fun_400c35
    puts("[+] Done!");
    puts("[+] Saving encrypted QR...");
    Output(plVar1,local_24,argv[3]);    // 400ca0
    puts("[+] Done!");
  }
  if (local_20 == *(long *)(in_FS_OFFSET + 0x28)) {
    return (ulong)(argc < 4);
  }
                    /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}

LoadQrとLoadKeyはだいたい察しがつくので、Encryptを見る

void Encrypt(long param_1,int *param_2)
{
  long *y_o;
  long *y_p;
  int d;
  int y;
  long x_o;
  int x;
  long x_p;
  int iVar1;

  do {
    if (param_2 == (int *)0x0) {
      return;
    }
    d = param_2[2];
    x = *param_2;
    x_o = (long)x;
    y = param_2[1];
    iVar1 = y;
    if (d == 1) {
      x = x + 1;
    }
    else {
      if (d < 2) {
        if (d == 0) {
          x = x + -1;
        }
        else {
LAB_00400c70:
          iVar1 = y;
        }
      }
      else {
        if (d == 2) {
          iVar1 = y + -1;
        }
        else {
          iVar1 = y + 1;
          if (d != 3) goto LAB_00400c70;
        }
      }
    }
    y_o = (long *)(param_1 + (long)y * 8);
    x_p = (long)x;
    y_p = (long *)(param_1 + (long)iVar1 * 8);
    *(char *)(*y_o + x_o) = *(char *)(*y_o + x_o) + *(char *)(*y_p + x_p);
    *(char *)(*y_p + x_p) = *(char *)(*y_o + x_o) - *(char *)(*y_p + x_p);
    *(char *)(x_o + *y_o) = *(char *)(x_o + *y_o) - *(char *)(*y_p + x_p);
    param_2 = *(int **)(param_2 + 4);
  } while( true );
}

あとはこの関数の逆の処理を書けばいいだけ

#!/usr/bin/env python3
from PIL import Image

key = []
qr = []

def load():
    keysrc = open("./key", 'r')
    qrsrc = open("./encrypted.qr", 'r')

    l = keysrc.readline()
    while l:
        try:
            d, p = l.split('#')
        except:
            l = keysrc.readline()
            continue
        p = eval(p)
        d = int(d)
        key.append((d, p))
        l = keysrc.readline()

    buf = []
    c = qrsrc.read(1)
    while c:
        if c == '1':
            buf.append(1)
        elif c == '0':
            buf.append(0)
        else:
            qr.append(buf)
            buf = []
        c = qrsrc.read(1)

def decrypt():
    for (d, (x, y)) in key:
        xo = x
        yo = y
        if d == 0:
            x -= 1
        elif d == 1:
            x += 1
        elif d == 2:
            y -= 1
        elif d == 3:
            y += 1

        qr[yo][xo] = qr[yo][xo] + qr[y][x]
        qr[y][x] = qr[yo][xo] - qr[y][x]
        qr[yo][xo] = qr[yo][xo] - qr[y][x]

def export():
    img = Image.new("RGB", (25, 25), (255, 255, 255))

    for i in range(25):
        for j in range(25):
            if qr[i][j] == 1:
                img.putpixel((i, j), (0, 0, 0))
            elif qr[i][j] == 0:
                img.putpixel((i, j), (255, 255, 255))
            else:
                for i in qr:
                    print(i)
                exit()

    img.save("out.png")

if __name__ == "__main__":
    load()
    decrypt()
    export()

出力されたQRコードをデコードするとflag

ddecode

zer0pts{puzzl3puzzl3}