arrow_backUS Cyber Games 2026
Forensicsmedium

Nintendo DS

by Pavel Knespl (capyplivl)

A JPEG of a Nintendo DS with a custom container appended after the image data. The container holds a homebrew DS framebuffer program; running it draws the flag on screen, so the flag only appears once the ARM payload is executed.

Solve

  1. The file is far larger than the visible JPEG. The image ends near byte 59620 and a USCG CTF marker sits in the trailing data:
    binwalk nintendo-ds.jpg
    strings -n5 nintendo-ds.jpg | grep -i uscg
    
  2. Carve from the USCG CTF marker (offset 59904). The container header is USCG CTF\x00\x00\x00\x00USCG01\x00\x00. The same bytes are a valid DS ROM (file reports Nintendo DS ROM image: "USCG CTF" (USCG01) homebrew):
    python3 -c "d=open('nintendo-ds.jpg','rb').read(); i=d.find(b'USCG CTF'); open('core.bin','wb').write(d[i:])"
    
  3. The ARM body starts at offset 0x200 inside the container. Slice it out:
    python3 -c "d=open('core.bin','rb').read(); open('arm.bin','wb').write(d[0x200:])"
    
    Disassembling it (capstone, CS_ARCH_ARM/CS_MODE_ARM) shows 32-bit ARM writing DS hardware registers: 0x4000000 (DISPCNT/POWCNT), 0x4000240 (VRAMCNT_A), 0x6800000 (VRAM bank A in LCDC mode). DISPCNT is set to 0x20000, so VRAM_A is shown directly as a 256x192 BGR555 framebuffer.
  4. Emulate the payload with Unicorn, run to its terminal b . loop at 0x1600, read back VRAM_A, and render to PNG:
    python3 emu.py
    
    from unicorn import *
    mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
    mu.mem_map(0x0, 0x100000); mu.mem_write(0x0, open('arm.bin','rb').read())
    mu.mem_map(0x04000000, 0x100000)
    mu.mem_map(0x06000000, 0x01000000)
    mu.mem_map(0x03000000, 0x100000); mu.reg_write(UC_ARM_REG_SP, 0x03080000)
    mu.emu_start(0x0, 0x1600, count=50_000_000)
    fb = mu.mem_read(0x06800000, 256*192*2)
    
  5. The rendered framebuffer shows the flag in white on a blue background, with "US CYBER GAMES" along the bottom.

Flag: SVIUSCG{WHICH_EMULATOR_DID_YOU_USE?}