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
- The file is far larger than the visible JPEG. The image ends near byte 59620 and a
USCG CTFmarker sits in the trailing data:binwalk nintendo-ds.jpg strings -n5 nintendo-ds.jpg | grep -i uscg - Carve from the
USCG CTFmarker (offset 59904). The container header isUSCG CTF\x00\x00\x00\x00USCG01\x00\x00. The same bytes are a valid DS ROM (filereportsNintendo 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:])" - The ARM body starts at offset 0x200 inside the container. Slice it out:
Disassembling it (capstone,python3 -c "d=open('core.bin','rb').read(); open('arm.bin','wb').write(d[0x200:])"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 to0x20000, so VRAM_A is shown directly as a 256x192 BGR555 framebuffer. - Emulate the payload with Unicorn, run to its terminal
b .loop at0x1600, read back VRAM_A, and render to PNG:python3 emu.pyfrom 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) - 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?}