A principios de noviembre de 2026, el desarrollador e investigador de ingeniería inversa Andrew Spode publicó los detalles de un hack de hardware sobresaliente: logró portar y ejecutar con éxito el clásico shooter DOOM en una cámara de juguete infantil comprada por internet por apenas unos diez euros. El juego se ejecuta con total funcionalidad —desplazamiento, giros y disparos— renderizando a unos fluidos 30 fotogramas por segundo, acompañado de efectos de sonido polifónicos y música de fondo.
Por fuera, el dispositivo presenta una tosca carcasa de plástico con motivos de dibujos animados. La caja no incluye marca comercial ni nombre de fabricante; la única referencia en el manual es el código “X9S”. Sin embargo, oculto bajo el plástico se encuentra un SoC chino de 32 bits: el HX3302B.
Para recortar costes hasta el límite, la cadena de suministro de productos de marca blanca recurre a soluciones de microcontroladores llave en mano preexistentes. Como consecuencia, este juguete económico cuenta con una potencia de cálculo que excede con creces las necesidades de una cámara básica. Para acelerar los tiempos de lanzamiento al mercado, el firmware genérico prescindió de cualquier mecanismo de seguridad elemental, convirtiendo el juguete en un banco de pruebas inmejorable para la ingeniería inversa.
Figura: La cámara infantil ejecutando DOOM a 30 FPS en su pequeña pantalla a color. Fuente: Spode’s Abode.
DOOM en 891 KB de memoria libre: un juguete de bajo coste con 120 MIPS
Antes del desmontaje, era casi imposible encontrar documentación técnica sobre el modelo en internet. La única pista útil se encontraba en los metadatos EXIF de las fotos de prueba: el campo del fabricante indicaba “HX-Tech”, nombre que coincidía con análisis de hardware previos realizados por el hacker Jeroen Domburg.
Spode desoldó los cables de la batería y extrajo la placa base. En el centro de la PCB descansaba el SoC HX3302B acompañado de una memoria flash SPI de 4 MB en encapsulado de 8 pines. Tras volcar el contenido con un programador y analizar el binario, confirmó que el núcleo de la CPU utiliza el conjunto de instrucciones OpenRISC.
Los microbenchmarks revelaron el perfil computacional del chip. Este procesador de bajo consumo cuenta con 8 KB de caché L1 de instrucciones y 8 KB de datos, con una tasa de transferencia de caché de 164 MB/s. El chip alcanza picos de 120 MIPS y sostiene unos 82 MIPS incluso ante frecuentes fallos de predicción de saltos. Un rendimiento más que suficiente para procesar los cálculos de proyección y renderizado 3D de un juego de hace más de tres décadas.
El verdadero escollo residía en la memoria RAM. El sistema apenas dispone de 2 MB de RAM física (con una velocidad de lectura de 65 MB/s). Dado que los procesos del sistema y el búfer de pantalla ocupan la mayor parte del espacio, el heap disponible para código de terceros quedó reducido a 891 KB. Aunque sobraban ciclos de reloj, el motor gráfico debía encajar en menos de 1 MB de memoria de trabajo.
Figura: El SoC HX3302B y el chip de memoria flash de 8 pines en la placa. Fuente: Spode’s Abode.
Volcado ciego de firmware vía EXIF: diseños genéricos sin validación alguna
El canal de actualización de firmware ofreció la primera vía de entrada. Al encenderse, la cámara busca en la raíz de la tarjeta SD un archivo llamado Xly100s.bin. Pese a que la cabecera del binario incluye un campo para checksums, la rutina de flasheo del bootloader nunca llega a comprobar el hash.
Asimismo, el actualizador aplica un mecanismo de sobreescritura directa: la escritura comienza desde la dirección base de la memoria flash y abarca únicamente la longitud del archivo de entrada. Si se carga un archivo de 1 MB, la cámara solo sobreescribe el primer megabyte, dejando intactos los 3 MB restantes. Cambiar la marca de tiempo de la cabecera basta para forzar el flasheo, convirtiendo la ranura SD en una vía abierta para la inyección de código sin firma.
Una vez habilitada la escritura, faltaba mapear la memoria interna. Spode ideó una solución ingeniosa: volcar la memoria directamente dentro de la cabecera EXIF de las fotografías capturadas. El estándar JPEG permite almacenar hasta 64 KB de metadatos EXIF, pero el software original de la cámara solo consumía unos 730 bytes.
Spode parcheó la rutina de guardado de imágenes. Debido a que el codificador JPEG por hardware no puede acceder de forma directa a la memoria de arranque interna, utilizó la CPU para transferir bloques de memoria al búfer EXIF. Cada pulsación del disparador extraía 4 KB de datos y desplazaba el puntero al bloque siguiente. Tras 16 disparos continuos, los 64 KB de la memoria de arranque se grabaron limpiamente en la tarjeta SD. El volcado confirmó la ausencia de mask ROM bloqueadas: todo el código de bajo nivel estaba al descubierto.
29 KB de bucle principal en RAM: ejecución XIP para superar la barrera de los 4 MB
La versión original de DOOM para PC requería un mínimo de 4 MB de RAM. Adaptarlo a un entorno con 891 KB libres obligó a rediseñar la gestión de memoria desde sus cimientos. Spode purgó los búferes inactivos de la cámara, logrando rescatar hasta 1,4 MB de heap disponible.
No obstante, esta memoria recuperada sufría de una fuerte fragmentación. Las asignaciones contiguas de cierto tamaño fallaban sistemáticamente, ya que el motor clásico dispersaba objetos en bloques aislados. Spode implementó un pool de memoria específico para asignaciones pequeñas y configuró los recursos de niveles y sonidos para ser liberados inmediatamente tras superar cada escenario.
La distribución del código constituyó otro reto técnico. El binario compilado de 260 KB no cabía en RAM junto con los recursos del juego. El chip soporta ejecución directa desde la memoria flash SPI (XIP), pero las pruebas demostraron que ejecutar instrucciones en flash resultaba 18 veces más lento que en la memoria RAM interna.
El análisis del binario mediante un emulador dio con la clave: el 99% del tiempo de ejecución total se consumía en un bucle principal de tan solo 29 KB de código. El resto correspondía a la inicialización y a los menús. Spode bloqueó esos 29 KB críticos en la RAM física de forma permanente, dejando el código restante para ser ejecutado bajo demanda desde la flash mediante XIP. Esta partición inteligente permitió que el juego funcionara a plena velocidad sin desbordar la memoria.
Figura: Aspecto exterior de la cámara de juguete genérica X9S. Fuente: Spode’s Abode.
Evasión del bucle de eventos y sintetizador propio: polling directo a 30 FPS
Una vez resuelto el problema de la memoria, la arquitectura del firmware limitaba la tasa de refresco. El sistema original utilizaba un bucle cooperativo de eventos cuya sobrecarga por fotograma alcanzaba los 38 milisegundos, reduciendo el rendimiento a la mitad.
Spode prescindió por completo del framework de eventos del fabricante y escribió un bucle de polling directo y minimalista. El código lee directamente los registros GPIO de la placa: la cruceta controla el desplazamiento, el disparador acciona el fuego continuo, una pulsación corta del botón de encendido cambia de arma, una pulsación prolongada abre el menú de opciones y chocar contra las paredes acciona las puertas. Al suprimir la sobrecarga de despacho, la tasa de fotogramas alcanzó unos sólidos 30 FPS.
El apartado de audio también presentaba serias limitaciones: la placa únicamente integra una salida mono por modulación de ancho de pulso (PWM). Spode programó un mezclador por software para combinar múltiples pistas de efectos sonoros en un único flujo de audio PCM.
La banda sonora se resolvió sin chips de sonido dedicados. La música original de DOOM fue compuesta en formato MUS para chips de síntesis FM, ausentes en esta placa. Spode desarrolló un sintetizador de software ultraligero que apenas consume un 2% de la CPU. Generando ondas cuadradas y triangulares, produce una melodía polifónica de 16 voces que reproduce con total fidelidad la banda sonora original a través del diminuto altavoz integrado.
Ejecución arbitraria vía SCSI: flasheo por USB sin necesidad de abrir el chasis
Una vez completado el port, el autor buscó una vía para compartir el proyecto con la comunidad. Distribuir el binario modificado con los assets del juego conllevaba riesgos de propiedad intelectual, lo que hacía indispensable un método de extracción no destructivo y libre de soldaduras.
La interfaz USB de almacenamiento masivo escondía una vulnerabilidad elemental. Al conectarse en modo de almacenamiento, el controlador responde a comandos SCSI específicos de fabricante no documentados. El ordenador puede enviar paquetes de control ordenando al chip saltar a una dirección de memoria RAM específica y ejecutarla. Spode programó una sonda de memoria inyectada mediante SCSI: el microcódigo se carga en RAM y el procesador se encarga de leer los 4 MB de la flash SPI y retransmitirlos en paquetes hacia el PC.
Cualquier usuario puede ahora realizar una copia de seguridad íntegra del firmware en pocos segundos con un simple cable USB. Las interfaces de depuración olvidadas en el diseño genérico acabaron por demoler la frágil barrera de seguridad del dispositivo.
El mercado de productos electrónicos de diez euros funciona bajo márgenes diminutos y plazos de entrega asfixiantes. Para economizar céntimos y semanas de desarrollo, los fabricantes inundan las tiendas con plataformas genéricas que combinan un excedente notable de potencia con una ausencia absoluta de seguridad. Una vez que salen de la fábrica, estos dispositivos se independizan de sus creadores. La comunidad de hackers ha vuelto a demostrar que hasta el aparato más olvidado de marca blanca puede reconvertirse, gracias a la ingeniería inversa, en una versátil plataforma de computación abierta.
Enlaces de referencia:
- Artículo especial en Hackaday
- Blog de ingeniería inversa de Spode’s Abode
- Análisis de firmware de cámaras infantiles por Sprite_tm