tiny runes

The objective is to decode the message in the lines4.bin by reverse engineering the file format.

By opening the lines4.bin in hex editor, we can see that it contains the magic header \x89PNG at offset 0x24, thus it contains a PNG image.

The image can be carved by removing the preceeding bytes:

This image seems to be a character set. The charset is the same in every bin file.

After removing the image data, we are left with the following bytes (lines1.bin):

The following decoded lines were provided by the author for lines1.bin:

The LiNe seems to be the line data structure header. The four next bytes is the line size: 00 00 00 3C.

By looking at the decoded data and similarly repeating bytes in the encoded data, one can see that bytes 05 09 correspond to dot.

By looking at the charset image, 05 seems to be the column and 09 is the row.

Now the lines4.bin can be decoded by converting the image to a 2D list and by using the LiNe header to locate the line data:

import struct

filename = "lines4.bin"

data = None

with open(filename, 'rb') as f:
  data = f.read()


LINE_HDR = "LiNe".encode("utf-8")

# For each row

CHARSET = [
  ['Q', '?', '0', '\\', 'H', '$', 'Y', ','],
  ['R', '-', 'L', '^', 'K', 'J', '', 'k'],
  ['s', '#', '_', '/', 'm', '=', 'f', '9'],
  ['7', 'd', '-', 'N', 'E', '4', 'q', 'r'],
  ['P', 'i', '', 'V', '`', '&', 'X', 'A'],
  ['n', '3', 'I', '', 'O', '*', ';', 'Z'],
  ['w', 'G', 'p', 'B', '8', 'c', 'S', 'j'],
  ['F', 'g', ':', 'e', 'b', 'y', '"', 'v'],
  ['%', '+', '', '1', ' ', '!', 'M', '©'],
  ['h', '{', '2', 'x', 'W', '.', 'D', '}'],
  ['t', 'U', '|', 'C', 'T', 'z', '6', 'u'],
  ['|', 'o', '>', 'a', '5', 'l', '<', '\'']
]

def parse_line(line_bytes):
  line_len = struct.unpack(">I", line_bytes[:4])[0]
  # print("Line len: %d" % line_len)

  idx = 4
  line = ""
  while idx <= (line_len + 2):
    col = line_bytes[idx]
    row = line_bytes[idx+1]
    # print("%d, %d" % (col, row))

    char = CHARSET[row][col]
    line += char
    idx += 2
  return line

def find_lines(data):
  line_offsets = []
  for i in range(len(data)):
    current_hdr = data[i:i+4]
    if current_hdr == LINE_HDR:
      line_offsets.append(i + 4)
  return line_offsets


lines = find_lines(data)

for line in lines:
  print(parse_line(data[line:]))

The flag is:

Jock: "0h my God! JC! A flag!"
JC Denton: "A flag! AOTW{wh4t_4_r0tt3n_fi13_f0rm4t}"