Solution de benoitlab pour Chip and Fish

misc

1 mars 2025

Table des matières

Contexte

Trouver un moyen d’afficher le flag qui se trouve au début de la pile de l’émulateur CHIP-8

Analyse

Il va falloir déterminer où se trouve l’adresse de début de la pile. Le programme challenge1.py nous donne un indice avec la ligne:

...
    vm.untrusted_ctx.memory.data[Memory.O_STACK:Memory.O_STACK + len(FLAG_LV1)] = FLAG_LV1
...

Le début de la pile est donc Memory.O_STACK qui est définie dans le fichier components/memory.py et vaut 0x0EA0:

...
class Memory(collections.UserList):
    SIZE    = 0x1000
    O_ROM   = 0x0200
    O_STACK = 0x0EA0
...

Le fichier components/cu.py définit tous les opcodes. Parmi ceux-ci on recherche ceux qui seront utiles pour récupérer les 16 octets situés à partir de l’adresse Memory.O_STACK:

  • Annn : charge registre i avec valeur nnn
  • Fx65 : charge registre v[x] avec valeur memory[i]

Maintenant que l’on sait comment récupérer un octet, on cherche comment l’afficher.

Dans la liste des opcodes il y a Dyxn:

...
                    self.cpu.processor.cf = self.cpu.context.io.display.update(
                        self.cpu.processor.i,
                        self.cpu.processor.v[y],
                        self.cpu.processor.v[x],
                        n
...

Cette fonction affiche à la position x, y de l’écran les n lignes d’un buffer contenant les chiffres hexadécimaux 0-9a-f sous forme de pixels 4x5 en commençant à la position i du buffer.

Exemple:

Cette suite d’opcodes affiche 7:

6007 # set v[0] to value to display, 7
F029 # multiply v[0] by 5
6E00 # set v[e] to 0, x coordinates
6F00 # set v[f] to 0, y coordinates
DEF5 # display
FFFF # end prog
$ nc localhost 40000
hex encoded rom:
6007F0296E006F00DEF5FFFF

chip_and_fish_01

Maintenant que l’on sait comment récupérer un octet et afficher un chiffre hexadecimal, le programme generate_ram.py suivant permet de créer la suite des opcodes permettant d’afficher le flag:

def init():
  print(f'610F', end='') # v[1]  = 0x0f (used as mask)

def display_char():
  global x_term, y_term

  # x coordinates
  val_x = f'{x_term:02X}'
  print(f'6E{val_x}', end='') # v[14] = val_x

  # y coordinates
  val_y = f'{y_term:02X}'
  print(f'6F{val_y}', end='') # v[15] = val_y

  # display char
  print(f'DEF5', end='')      # display

  # move cursor
  x_term = x_term + 5
  if x_term == 40:
    x_term = 0
    y_term = y_term + 6

def print_addr(adress):
  print(f'A{adress}', end='') # i = addr
  print(f'F065', end='')      # v[0] = memory[i]
  print(f'8200', end='')      # v{2] = v[0]
  print(f'8206', end='')      # v[2] >> 1
  print(f'8206', end='')      # v[2] >> 1
  print(f'8206', end='')      # v[2] >> 1
  print(f'8206', end='')      # v[2] >> 1
  print(f'F229', end='')      # i = v[2] * 5
  display_char()
  print(f'8012', end='')      # v[0] & v[1]
  print(f'F029', end='')      # i = v[0] * 5
  display_char()

def end():
  print(f'FFFF', end='')      # end

x_term = 0
y_term = 0
addr   = 'EA0'

init()

while addr != 'EB0':
  print_addr(addr)

  value = int(addr, base=16)
  value = value + 1
  addr  = f'{value:03X}'

end()
$ python3 generate_ram.py
610FAEA0F06582008206820682068206F2296E006F00DEF58012F0296E056F00DEF5AEA1F06582008206820682068206F2296E0A6F00DEF58012F0296E0F6F00DEF5AEA2F06582008206820682068206F2296E146F00DEF58012F0296E196F00DEF5AEA3F06582008206820682068206F2296E1E6F00DEF58012F0296E236F00DEF5AEA4F06582008206820682068206F2296E006F06DEF58012F0296E056F06DEF5AEA5F06582008206820682068206F2296E0A6F06DEF58012F0296E0F6F06DEF5AEA6F06582008206820682068206F2296E146F06DEF58012F0296E196F06DEF5AEA7F06582008206820682068206F2296E1E6F06DEF58012F0296E236F06DEF5AEA8F06582008206820682068206F2296E006F0CDEF58012F0296E056F0CDEF5AEA9F06582008206820682068206F2296E0A6F0CDEF58012F0296E0F6F0CDEF5AEAAF06582008206820682068206F2296E146F0CDEF58012F0296E196F0CDEF5AEABF06582008206820682068206F2296E1E6F0CDEF58012F0296E236F0CDEF5AEACF06582008206820682068206F2296E006F12DEF58012F0296E056F12DEF5AEADF06582008206820682068206F2296E0A6F12DEF58012F0296E0F6F12DEF5AEAEF06582008206820682068206F2296E146F12DEF58012F0296E196F12DEF5AEAFF06582008206820682068206F2296E1E6F12DEF58012F0296E236F12DEF5FFFF
$ nc localhost 40000
610FAEA0F06582008206820682068206F2296E006F00DEF58012F0296E056F00DEF5AEA1F06582008206820682068206F2296E0A6F00DEF58012F0296E0F6F00DEF5AEA2F06582008206820682068206F2296E146F00DEF58012F0296E196F00DEF5AEA3F06582008206820682068206F2296E1E6F00DEF58012F0296E236F00DEF5AEA4F06582008206820682068206F2296E006F06DEF58012F0296E056F06DEF5AEA5F06582008206820682068206F2296E0A6F06DEF58012F0296E0F6F06DEF5AEA6F06582008206820682068206F2296E146F06DEF58012F0296E196F06DEF5AEA7F06582008206820682068206F2296E1E6F06DEF58012F0296E236F06DEF5AEA8F06582008206820682068206F2296E006F0CDEF58012F0296E056F0CDEF5AEA9F06582008206820682068206F2296E0A6F0CDEF58012F0296E0F6F0CDEF5AEAAF06582008206820682068206F2296E146F0CDEF58012F0296E196F0CDEF5AEABF06582008206820682068206F2296E1E6F0CDEF58012F0296E236F0CDEF5AEACF06582008206820682068206F2296E006F12DEF58012F0296E056F12DEF5AEADF06582008206820682068206F2296E0A6F12DEF58012F0296E0F6F12DEF5AEAEF06582008206820682068206F2296E146F12DEF58012F0296E196F12DEF5AEAFF06582008206820682068206F2296E1E6F12DEF58012F0296E236F12DEF5FFFF

chip_and_fish_02

Flag: FCSC{e50f91bc6418a7a79b0c3fe74bb5e600}