Running DOOM on a Budget Toy Camera: Generic Firmware Becomes a Hacker Playground

Running DOOM on a Budget Toy Camera: Generic Firmware Becomes a Hacker Playground

DOOMHardware Reverse EngineeringFirmware HackingEmbedded SystemsHX3302BConsumer Electronics

Sources:Hackaday + Spode's Abode

In early November 2026, reverse engineering enthusiast Andrew Spode documented an impressive hardware hack. After ordering an unbranded children’s toy camera online for less than fifteen dollars, he successfully ported and ran the classic first-person shooter DOOM. The port delivers full gameplay—strafing, turning, and shooting—rendering smoothly at roughly 30 frames per second alongside polyphonic sound effects and background music.

On the outside, the camera features a cheap plastic casing decorated with cartoon patterns. The retail box carries no manufacturer name or trademark, and the only identifier in the manual is the model designation “X9S.” Underneath the plastic shell, however, sits a 32-bit HX3302B SoC.

To drive manufacturing costs down to the absolute minimum, the white-label supply chain routinely adopts off-the-shelf turnkey application processor solutions. As a result, this disposable toy contains processing power far beyond what basic photography requires. Rushed to market on boilerplate reference designs, the firmware omits virtually all basic security defenses—transforming a locked-down kids’ toy into a fertile playground for hardware reverse engineering.

DOOM running smoothly on the small screen of a children's toy camera Figure: The children’s toy camera running DOOM at 30 FPS on its small color display. Source: Spode’s Abode.

Running DOOM in 891KB of RAM: A Fifteen-Dollar Toy Hiding 120 MIPS

Prior to opening the enclosure, almost no technical documentation existed online for the device. The only clue came from the EXIF metadata of test shots: the camera manufacturer field read “HX-Tech,” a name previously encountered in teardowns by hardware hacker Jeroen Domburg.

Spode desoldered the battery leads and extracted the printed circuit board. At the core of the board was an HX3302B SoC paired with an 8-pin 4MB SPI flash chip. Using an external programmer to dump the flash, reverse engineering revealed that the processor core implements the OpenRISC architecture.

Microbenchmarks quickly mapped out the chip’s computational profile. This low-power processor features an 8KB L1 instruction cache and an 8KB data cache, with cache throughput reaching 164 MB/s. The core delivers up to 120 MIPS under optimal conditions and sustains around 82 MIPS even under frequent branch mispredictions. That level of computational throughput easily surpasses what is required to handle the ray-casting and projection math of a thirty-year-old 3D engine.

The real bottleneck was memory capacity. The SoC integrates just 2MB of physical RAM, clocked at 65 MB/s. With system tasks and the display framebuffer claiming the lion’s share, only 891KB of free heap remained for user applications. While CPU cycles were plenty, the entire engine had to squeeze into less than 1MB of working memory.

Teardown of the toy camera mainboard showing the SoC and flash memory Figure: The HX3302B SoC and 8-pin flash memory chip on the toy camera PCB. Source: Spode’s Abode.

Blind Firmware Extraction via EXIF: Reference Designs Skipping Security Checks

The built-in firmware upgrade routine provided the first opening. On boot, the camera checks the root of an inserted SD card for a file named Xly100s.bin. While the binary header contains a designated checksum field, the bootloader’s updater code never actually validates the hash.

Furthermore, the flashing routine employs partial in-place overwriting: erasing and writing begins from the base offset of flash memory, proceeding only for the byte length of the incoming file. Flashing a 1MB file overwrites merely the first 1MB, leaving the remaining 3MB of flash intact. Simply altering the header timestamp triggers an update, turning the micro-SD slot into an unauthenticated code injection conduit.

With write access established, Spode needed to inspect the internal memory layout. He devised an ingenious exfiltration technique: dumping memory contents into the EXIF headers of captured photos. Standard JPEG specifications allow up to 64KB of metadata in an EXIF block, yet the camera’s stock software only utilized about 730 bytes.

Spode patched the camera’s image-saving routine. Because the dedicated hardware JPEG encoder could not read internal boot memory directly, he used the CPU to copy target memory regions in chunks into the EXIF staging buffer. Every shutter press captured 4KB of internal memory, advancing a window pointer across consecutive captures. After 16 shots, the full 64KB boot memory was cleanly written to the SD card. Disassembly confirmed that no on-chip mask ROM was locked away—the entire low-level codebase was fully exposed.

29KB Core Engine in RAM: XIP Offloading Breaks the 4MB Barrier

Vanilla DOOM on PC originally required at least 4MB of RAM. Squeezing it into 891KB demanded a radical overhaul of the game’s memory management. By stripping unused camera buffers and reclaimed scrap memory, Spode managed to cobble together approximately 1.4MB of usable heap.

However, this reclaimed heap suffered from severe fragmentation. Allocating larger contiguous buffers frequently failed because the original engine made numerous scattered, unpooled allocations. Spode implemented dedicated memory pools for small structures and configured level geometry and audio assets to be freed immediately upon completion, preventing memory leaks and heap exhaustion.

Code placement posed another major hurdle. The compiled 260KB binary could not comfortably live in RAM alongside game assets. The HX3302B supports execute-in-place (XIP) directly over SPI flash, but benchmarks revealed that XIP execution was 18 times slower than running code from internal RAM.

Profiling the engine in an emulator provided the crucial breakthrough: 99% of total execution time was spent within an inner loop spanning just 29KB of machine code. The remaining binary consisted mostly of one-time initialization, menu rendering, and cold logic paths. Spode pinned this 29KB hot loop permanently into physical RAM, while leaving the cold paths to execute directly from flash via XIP on demand. This tiered execution strategy allowed the engine to run at full speed without blowing past the RAM limit.

Front view and button layout of the children's toy camera Figure: The unbranded X9S children’s toy camera exterior and controls. Source: Spode’s Abode.

Bypassing the Main Loop & Custom Synth: Direct Polling Unlocks 30 FPS

With memory constraints resolved, the original firmware architecture emerged as the next performance bottleneck. The vendor OS relied on a cooperative event loop where single-frame event dispatching incurred up to 38 milliseconds of overhead, cutting the frame rate in half.

Spode bypassed the vendor event framework entirely, replacing it with a minimal bare-metal polling loop. The new loop directly reads hardware GPIO registers: the directional buttons handle movement, the shutter button handles firing, quick presses on the power button cycle weapons, long presses bring up the menu, and running against walls triggers door interactions. Eliminating the scheduling overhead allowed the renderer to hit a consistent 30 FPS.

Audio presented another constraint, as the board provides only a single PWM output channel. Spode wrote a lightweight software audio mixer to blend multiple sound effect channels down into a single PCM stream.

Background music was handled without dedicated sound hardware. Original DOOM music was composed in MUS format and played via FM synthesis chips like the Yamaha OPL2/OPL3. The toy camera had no FM synthesizer. Spode engineered an ultra-lightweight software waveform synthesizer that consumes just 2% of CPU time. By generating square and triangle waves, it achieves 16-voice polyphony, reproducing the iconic soundtrack authentically through the camera’s tiny onboard speaker.

Arbitrary Execution via SCSI: Zero-Disassembly Flashing Over USB

Having achieved a working port, Spode sought an easy way to distribute the hack to the community. Distributing pre-compiled firmware images raised copyright concerns with game assets, making a solderless, non-destructive flashing tool essential.

The camera’s USB mass storage interface harbored a glaring architectural vulnerability. When mounted as a mass storage device, the controller responded to undocumented vendor-specific SCSI commands. The host PC could transmit custom command packets instructing the SoC to jump directly to an arbitrary RAM address and begin execution. Spode developed a lightweight probe payload: over standard SCSI commands, the host pushes microcode into RAM, which then reads out the entire 4MB SPI flash and streams it back over the USB cable.

End users can now perform a complete, non-destructive firmware dump in just seconds using a standard USB cable. Flaws and debug channels left behind in generic reference hardware completely dismantled what little perimeter defense the device had.

The sub-fifteen-dollar consumer electronics market is driven by razor-thin margins and ultra-fast turnaround times. To shave pennies and weeks off production schedules, manufacturers flood the market with unhardened reference hardware carrying substantial compute overhead. Once these devices leave the factory, their flimsy architectures break free of manufacturer control. As the hacker community proves once again, even the most neglected white-label gadget can be transformed into a versatile, open computing platform through reverse engineering.

Reference Links:

  • Hackaday Feature
  • Spode’s Abode Reverse Engineering Blog
  • Sprite_tm Children’s Camera Teardown