¿Objetivo?
Todos los juegos para GameBoy Advance (GBA) y Nintendo DS tienen unos datos al principio del archivo (header) que los usa la consola para la inicialización del juego como el nombre, el código del desarrollador, las posiciones de memoria donde va el código, el punto de inicio del sistema de archivos... Sorprende ver entre estos datos un conjunto de bytes sin significado en ese contexto pero que, mirando en GBATEK parece ser el "Logo de Nintendo". Teóricamente, a partir de esos bytes se podría recrear esa imagen y es más, así lo hacen las consolas. En en juego para GBA estos datos se encuentran a partir de la posición 0x04 mientras que en uno de la DS en 0xC0, en ambos dispositivos este logo debe ocupar 0x9C bytes.
Logo de Nintendo en GBA. En el archivo solo aparece el de Nintendo, no el de GAME BOY. |
Lo primero que intento es comprobar si puedo ver ya directamente el logo. Para ello creo un archivo con los bytes 00 00 FF 7F que al abrir como paleta serán los colores negro y blanco respectivamente codificados en BGR555. A continuación usando Tinke abro los dos archivos, la paleta seleccionándola y pulsando 'P' y luego los datos del logo, igual y pulsando 'T'. El resultado final es este:
Datos en bruto, nada visible |
Cómo obtener la imagen
Lo primero que hice fue buscar en el sitio donde sabía que algo habría comentado, en GBATEK. Ahí está prácticamente toda la documentación técnica pública que existe entorno a GBA y NDS, todo investigado por Martin Korth en el desarrollo de su emulador no$gba, un emulador que a pesar de los años que lleva sin ser actualizado funciona perfectamente para juegos de la GBA y en bastantes de la NDS (a día de hoy, el mejor es DeSmuME). Concretamente, la información que queremos está en la sección GBA Cartridge Header donde encontramos lo que buscamos:
004h..09Fh - Nintendo Logo, 156 BytesSi vamos a la sección correspondiente de la DS vemos que nos dice que esos datos son iguales a los de GBA, así que nos concentraremos en la GBA (más tarde explicaré la diferencia entre las dos plataformas).
Contains the Nintendo logo which is displayed during the boot procedure.
Cartridge won't work if this data is missing or modified.
In detail: This area contains Huffman compression data (but excluding
the compression header which is hardcoded in the BIOS, so that it'd be
probably not possible to hack the GBA by producing de-compression buffer
overflows).
A copy of the compression data is stored in the BIOS, the GBA will
compare this data and lock-up itself if the BIOS data isn't exactly the
same as in the cartridge (or multiboot header). The only exception are
the two entries below which are allowed to have variable settings in
some bits.
Bueno, ya al menos tenemos una pista que explica el porqué de tan pocos bytes para una imagen, están comprimidos con Huffman (recomiendo leer este post de CUE sobre esta codificación: Algoritmo de Huffman (no adaptativo) y usar sus herramientas para ello) y porqué no la hemos podido visualizar. Lo que se me ocurrió entonces fue coger un descompresor de Huffman, añadirle yo a los datos del logo una cabecera estándar como:
28 FF FF FFConvencido de que funcionaría, no fue así... Con ambas compresiones obtuve dos archivos de 652 bytes que nada de sentido tenían. Bueno, como primer intento no quedó mal... (Ahora que he estudiado a fondo esta compresión me doy cuenta de la barbaridad que hice... Estaba claro que le faltaba el árbol (el segundo byte de un árbol no puede ser 0xFF))
* El 0x28 indica que los datos están comprimidos con Huffman 8bits, también habría que probar con 0x24 (4bits).
* Los bytes 0xFFFFFF indican el tamaño descomprimido, dado que este no lo sabemos ponemos el más grande. El programa nos avisará cuando termine la decodificación de que ese tamaño no corresponde al obtenido pero no es más que una advertencia, si está bien programado no deberíamos tener problemas.
No funcionó, así que lo siguiente que se me ocurrió fue ver como el juego leía esos datos y operaba con ellos, es decir, a por el código ensamblador. Para esta ocasión usaré no$gba, a pesar de que su interfaz es más sencilla, con menos opciones y un poco más difícil de dislumbrar lo que buscamos, es el único emulador para GBA con el que he trabajado y sé usarlo bien. Este programa es de pago ya que contiene el depurador, creo que ya no es posible conseguirlo porque según me dijeron el autor ya no contesta a los emails, está como desaparecido, de todas formas es cosa de cada uno el conseguirlo.
no$gba con el depurador |
[08000004]?Además, tenemos que indicarle al emulador que queremos que no se inicie el juego directamente, si no que ejecute la BIOS primero, como en una GBA original (si no nos saltamos lo que vamos buscando), eso se hace en: Options->Emulation Setup->Reset/Startup Entrypoint->GBA BIOS (Nintendo logo). Preparado todo, nos disponemos a comenzar nuestra sesión de depuración. La primera interrupción se hace en 0xB90 con las instrucciones (están en THUMB):
Eso indica que cuando se lea (símbolo ?) en la posición de memoria encerrada entre corchetes, se pare el emulador.
0xB8A cmp r5,r4Ese fragmento es un bucle que copia una serie de datos (r4 bytes) de r0 a r1, seguramente se estará ejecutando dentro de otro bucle mayor. Básicamente, ahí se está copiando nuestro logo a r1 (para trabajar con los bytes, estos no pueden estar en la zona donde está el cartucho, deben estar en 0x03yyyyyy 0x02yyyyyy). En este caso los está copiando a 0x03000088 (el valor de r1), luego ponemos otro PI ahí para saber que hace luego con ellos y continuamos la ejecución (con F9).
0xB8C bge #0xB96
0xB8E ldrh r3,[r0,r5]
0xB90 strh r3,[r1,r5]
0xB92 add r5,r5,2
0xB94 b #0xB8A
Como veréis de nuevo llegamos a ese trozo de código, esta vez está copiando de nuevo el logo de donde los había copiado antes a 0x030000588 luego ponemos otro PI allí (esperando que este sea el último), continuamos y...
El emulador se para ahora en 0x1072, delante nuestra tenemos la subrutina (comienza en 0x1014) que como veremos descomprime / descodifica los datos del logo usando el algoritmo Huffman:
Lo mejor para saber si esa es la subrutina que buscamos es ir ejecutando las instrucciones paso a paso (con F7). Obtenida la función hice un programilla en C# que hiciese exactamente lo mismo (lo podéis descargar al final de la entrada).
¡Ojo!, si reinicias el juego de forma que consigas ejecutar la subrutina desde el principio comprobarás que esta no comienza a leer datos desde 0x03000588, si no desde 0x03000564. ¿Qué sucede? Tal y como se comenta en GBATEK, lo que viene en la cabecera de los juegos son los datos comprimidos de la imagen, pero para descomprimirla, en Huffman se necesitan datos extras (los que forman el árbol) por eso nuestro primer intento salió mal. Los datos en cuestión que hay que añadir a los del logo para poder descomprimir son los siguientes (se encuentra en la BIOS):
24 D4 00 00 0F 40 00 00 00 01 81 82 82 83 0F 83
0C C3 03 83 01 83 04 C3 08 0E 02 C2 0D C2 07 0B
06 0A 05 09
Segundo intento |
Tras analizar esa subrutina vemos que todavía no termina la cosa de desencriptar, ahora resulta que para obtener los bytes originales de la imagen tenemos que sumar un byte detrás de otro. Bueno, actualizo de nuevo el programilla para que haga eso también... Y vemos si lo hemos conseguido:
Tercer intento, casiiiii |
Cuarto y último intento |
Cómo modificar el logo
Antes de pensar en cómo codificar de nuevo la imagen debemos saber un par de cosas de porqué aparecen esos datos en la cabecera de todo juego. Para ello continuaremos con la sesión de depuración en no$gba. Eliminamos todos los puntos de interrupción y dejamos solo el 0x03000088. Veremos que para muchas veces, una por cada frame de la animación del logo, tenemos que tener paciencia y esperar a que pase esa animación dándole a continuar, nos interesa ver lo que pasa justo después... Pues en ese momento se para en 0x0702. Analicemos esa subrutina que merece la pena, os la dejo aquí ya comentada (comienza en 0x6E8)
Resumamos las sorpresas:
1 .- Si queremos que la consola no se quede bloqueada (al devolver error entra en un bucle infinito) no podemos cambiar el logo pero... eso no es del todo cierto. Lo normal es que r4 valga siempre 0xFF para que se analicen todos los bits de todos los bytes, pero hay dos bytes del final, con los que deja que haya unos cuantos bits diferentes al original. De nuevo buscando en GBATEK damos con lo siguiente:
09Ch Bit 2,7 - Debugging Enable
This is part of the above Nintendo Logo area, and must be commonly set to 21h, however, Bit 2 and Bit 7 may be set to other values.
When both bits are set (ie. A5h), the FIQ/Undefined Instruction handler in the BIOS becomes unlocked, the handler then forwards these exceptions to the user handler in cartridge ROM (entry point defined in 80000B4h, see below).
Other bit combinations currently do not seem to have special functions.
09Eh Bit 0,1 - Cartridge Key Number MSBsResumiendo, son bits que se usan para activar funciones especiales de depuración, de hecho si probáis a cambiarlos el logo final será siendo el mismo. Así que no hay forma de modificar un logo.
This is part of the above Nintendo Logo area, and must be commonly set to F8h, however, Bit 0-1 may be set to other values.
During startup, the BIOS performs some dummy-reads from a stream of pre-defined addresses, even though these reads seem to be meaningless, they might be intended to unlock a read-protection inside of commercial cartridge. There are 16 pre-defined address streams - selected by a 4bit key number - of which the upper two bits are gained from 800009Eh Bit 0-1, and the lower two bits from a checksum across header bytes 09Dh..0B7h (bytewise XORed, divided by 40h).
2.- Otra curiosidad es que hace una segunda comprobación que no llego a entender: suma todos los bytes del nombre en clave del juego y si este resultado es mayor que 0xFFFF (65535, tamaño máximo de dos bytes), devuelve error. No le veo mucho sentido porque ese valor no se debería ni leer, para un usuario final ese nombre en clave no aparece nunca por ningún lado.
Conociendo esto aceptamos que no podemos modificar el logo si queremos que funcione porque en el emulador si hacemos que se lo salte no vemos el logo cambiado y si lo muestra no se ejecuta el juego (lo mismo en una consola)... Pero digamos que queremos sorprender a nuestros amigos y dejar la consola bloqueada con un logo propio, pues continuemos. Como sabréis en una codificacin Huffman hay una tabla con cada caracter ordenada por su número de apariciones con el objetivo de que los que más se repitan ocupen menos bits, veámoslo aquí con el árbol de este caso.
Árbol Huffman:
_____1E_____De ahí podemos sacar los codewords (los números son bits):
/ \
______1D______ 0
/ \
__1C__ __1B__
/ \ / \
1A 19 18 17
/ \ / \ / \ / \
F 16 C 15 3 14 1 13
/ \ / \ / \ / \
4 12 8 E 2 11 D 10
/ \ / \ / \
7 B 6 A 5 9
0: 1 1: 0110Codificar un archivo usando una tabla dada no es difícil, solo tenemos que sustituir cada 4bits por el codeword correspondiente, es decir, que donde haya un 5 (0101 en binario) miramos en los codewords y lo sustituimos por 011110 (es binario) y así. El problema es que el archivo final sea mayor que el original, entonces no podremos usar ese logo ya que solo se decodificaran los 0xD4 primeros bytes (los que indica la cabecera que está en la BIOS). Si es más pequeño no hay problema, lo rellenamos con 0x00. Dicho esto, me dispuse a actualizar de nuevo mi programilla para que codificara usando la tabla original.
2: 01010 3: 0100
4: 00010 5: 011110
6: 010110 7: 000110
8: 00110 9: 011111
A: 010111 B: 000111
C: 0010 D: 01110
E: 00111 F: 0000
De lo primero que me di cuenta es que los archivos no coincidían y no era problema de mi codificador. Los dos últimos bytes que obtenía eran 00 (los bytes en las posiciones 0x98 y 0x99, se escriben a la vez 4 bytes en low-endian) ya que no había más datos para codificar pero en el original estos valores están puestos a 0x21 y 0xD4. Lo que sucede es que la decodificación para cuando se obtienen todos los bytes que indica la cabecera (0xD4), si nos fijamos en el estado de cuando esto sucede vemos que no todos los codewords se han usado, de hecho hay 0x12 (18) bits que se quedan sin ser procesados pero que no tiene sentido procesarlos (hay como un codeword que no existe o que le faltan bits y no son bits de relleno puesto que hay un 1). Sin embargo eso no es un error. A partir del bit 18 de ese último uint (4 bytes juntos sin signo) comienzan los bits especiales de depuración que no pertenecen al logo (en GBATEK solo viene el significado de 4 de ellos, los que hemos dicho antes que son de depuración y no se comprueban). Por ello, cuando los modificábamos el logo no cambiaba, por que no se llegan a decodificar. Como esos bits no pertenecen a la codificación no queda más remedio que ponerlos a mano. Solucionado dicho problema de codificación solo me quedaba añadir la encriptación de suma siguiendo la siguiente fórmula:
encriptado_i = desencriptado_i - desencriptado_(i-1); // i=1,2,3...esas tres variables son valores de 16bits, las variables que pertenecían al desencriptado se van leyendo del logo, la imagen final, y el valor inicial de desencriptado_(i-1) (para i = 1) es 0.
Diferencias entre GBA y NDS
Hasta ahora todo lo comentado es referido a la GBA sin embargo, en la cabecera de los juegos de la Nintendo DS encontramos esos mismos datos, concretamente empiezan en 0xC0. La forma de obtener la imagen es igual pero cambia bastante la forma de cómo comprueba que sean los datos originales:
For the Logo checksum, the BIOS verifies only [15Ch]=CF56h, it does NOT verify the actual data at [0C0h-15Bh] (nor it's checksum), however, the data is verified by the firmware.Es decir, justo después en 0x15C hay un valor de 16bits que es el código CRC16 de los datos del logo. Ese código es el que comprueba la BIOS (no sé exactamente si lo calcula de nuevo o lo comprueba con uno fijo que tiene). Pero además, no contento con eso, el firmware comprueba que los datos sean los mismos. Para resumir, no hay forma de poder cambiarlo en la DS y que se pueda jugar. De nuevo, si lo cambias en los emuladores, tras una advertencia (en no$gba) se puede jugar ya que no hacen esa comprobación. Sin embargo lo he probado en mi DS con Wood (para M3) y no deja ejecutarlo, algo extraño porque si comprobáis el logo de un homebrew, por razones que comentaré abajo, es totalmente distinto al del Nintendo (y este no parece ser un logo porque lo intento extraer y me da error por todos lados). Tras un segundo intento donde a ese mismo juego le he puesto el mismo logo que viene en el homebrew ya he podido jugar, así que por lo visto Wood admite dos logos: uno para juegos comerciales y otro para homebrews.
ACTUALIZO: He probado en otras flascard y por ejemplo con M3 Sakura se puede ejecutar un juego con el logo cambiado sin problemas. Sin embargo con firmware de R4i Chrismas version, el juego se queda en blanco pillado.
Gracias al apunte de Nitehack en su comentario. En la DS sí que aparece, justo nada más encenderla antes de que se cargue el menú con opciones siempre y cuando haya un juego introducido. Ahí está la clave de algo que seguramente habremos visto todo pero que nunca no hemos parado a pensar porqué. Si no hay juego introducido, no aparece logo de Nintendo, ¡no lo puede leer! Esto implica que las flashcard deben de tener el logo de Nintendo porque de otra manera veríamos otra cosa, al menos en la DSi, entre otras porque no se puede arrancar el juego directamente, pero en las consolas anteriores... se puede iniciar directamente sin pasar por el menú (incluso con M3 DS Real se salta hasta esa advertencia), y esa puede ser la clave para que algunas flascard no lo hayan necesitado añadir. Finalmente os dejo una captura de DeSmuME con este logo en la DS.
El motivo del logo
Esta pequeña historia tiene ya su tiempo. Las primeras consolas portátiles de Nintendo (GB, GBC...) también traen un logo de Nintendo en la cabecera de sus juegos, ligeramente diferente y que analizaré en otra entrada (esto no tiene fin). El motivo es muy simple: evitar que se distribuyan juegos sin permiso de Nintendo. La verdad es que está muy bien y no tan bien pensado, el logo de Nintendo tiene copyright, pertenece a Nintendo y cualquiera no puede distribuirlo cuando quiera ni como quiera, por eso los homebrew y toda modificación de un juego original licenciado por Nintendo, no puede contenerlo porque estaría distribuyendo material con copyright sin permiso de Nintendo.
La consecuencias son varias, como hemos comentado antes, cualquier homebrew o parche no puede contenerlo, a parte ningún programa que sirva para modificar juegos puede contener esos bytes en su código. Ejemplo: fugbar, programa para arreglar cabeceras de juegos de la GBA
fuGBAr does NOT include this logo to correct rom headers, as it is illegal to store the logo within fuGBAr. It is copyrighted, and belongs to Nintendo. It can be argued that it's ok to include this copyrighted logo in your GBA works, since its required for the rom to actually work, but this tool is not a gba rom and we'd rather not deal with any legal harrassment.Otro, Turrican 3.5 un homebrew:
He is aware of the issue on real hardware. No header was put because of copyright reason (Nintendo logo in the header). So, officially :D, T2002 for GBA is for emulators only.¿Y esta acción por parte de Nintendo? Respuesta: ¿y cómo es que las tarjetas para backups funcionan en una GBA/NDS?, si la consola las confunde con un juego es porque tienen ese logo. Yo no lo sé, no sé si el chip que lleva la tarjeta hace que se salte ese y otros bloqueos antipiratería, pero en caso de que lo tuviera ¿no sería una buena estrategia para retirarlas del mercado?
Finalmente, ampliando la frase en negrita de la cita de fugbar os recomiendo leer esta historia. Y aquí os dejo un resumen:
El usuario Jeff Massung creador, según deja a entender, de un compilador de BASIC para la GBA le llegó un email de Nintendo pidiéndole que retirara de su compilador los bytes del logo porque era material protegido por copyright que ellos no querían que estuviesen ahí. Él preguntaba en el post que cómo podía hacer para ejecutar los juegos sin ese logo. El usuario Albert van der Horst le responde que no debe asustarse, lo que Jeff había hecho era legal porque no usaba el logo para obtener beneficios a partir de él y porque está obligado a poner esa cabecera para asegurar la interoperatividad y le recomienda luchar.Y así es, en Europa el artículo 6 de 1991 permite la decompilación con motivo de la interoperatividad algo que implica en algunos casos añadir datos como los datos del logo. Casos frecuentes es el de WhatsAPI, que al final no fue a ningún lado, pero el más conocido fue el de Sega y Accolade, un caso muy muy parecido al anterior:
Accolade, una empresa, puso en venta un videojuego para el cual tuvo que hacer ingeniería inversa y determinar que para que este funcionase tenía que contener el archivo del juego en una parte la palabra "SEGA" y si esa palabra no estaba el juego no se ejecutaba, exactamente como el logo de Nintendo, SEGA lo denunció por eso. Finalmente, el juez determinó que no había cometido ninguna ilegalidad, no había copiado código de SEGA y solo había puesto esa palabra para poder ejecutar su propio código.Y así es como debe ser, para evitar los monopolios en el mercado pero claro, quién ante una imponente carte de "cese y desista" de una gran compañía al menos no se plantea si merece la pena seguir (con tu proyecto y puede que ir a juicio) o parar.
Y hasta aquí la primera entrada de verdad, ha salido muuuy larga pero había mucho que explicar en este gran misterio que me perseguía desde que me inicié en este mundillo y que hasta ahora no he sido capaz de resolver. Espero que lo hayáis disfrutado tanto como yo ;).
Código de programa para extraer e importar logos de NDS y GBA: LogoGBA.cs
Primeramente Excelente entrada :)
ResponderEliminarEl logo de Nintendo en DS seguro que lo has visto pero se te habrá pasado. Aparece justo al encender la consola (obviamente con un juego insertado) pero aparece dentro de un óvalo. http://i75.servimg.com/u/f75/13/46/22/09/boot10.png
Yo diría que ese logo que aparece representado al encender la DS con un juego es el de la dirección 0xC0 (los pixeles coinciden exactamente con el de GBA)
Lo de las flash carts me parece interesante voy a investigar a ver, pero yo diría que están usando el logo para arrancar la tarjeta en vez de un método para saltárselo.
¡Un Saludo!
Gracias :)
EliminarRespecto al logo de la NDS tienes toda la razón, acabo de actualizar la entrada añadiendolo e incluso he puesto una captura con un logo modificado. El óvalo junto a las letras Nintendo DS son sprites que se añaden sobre él.
De hecho, esto implica que al menos las flashcard para DSi (donde no se podría saltar esa advertencia de seguridad) SÍ tienen que tenerlo, pues si no veríamos otra cosa...
Saludos