Autor Tema: Desencriptar WONDER BOY (set 1, 315-5177)  (Leído 2373 veces)

Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Desencriptar WONDER BOY (set 1, 315-5177)
« en: 11 de Julio de 2014, a las 20:07 horas »
Hola a todos.

Estoy intentando desencriptar esta ROM, y me he dado de bruces, así que pido ayuda a los expertos (Andreas, edcross, etc.). Con un código chorra, he conseguido desencriptar por un lado opcodes y por otro lado datos. El código es este:

Código: [Seleccionar]
/***************************************************************************
Decrypt
***************************************************************************/

#include <iostream>
#include <fstream>
#define BIT(x,n) (((x)>>(n))&1)
#define BITSWAP8(val,B7,B6,B5,B4,B3,B2,B1,B0) \
((BIT(val,B7) << 7) | (BIT(val,B6) << 6) | (BIT(val,B5) << 5) | (BIT(val,B4) << 4) | \
(BIT(val,B3) << 3) | (BIT(val,B2) << 2) | (BIT(val,B1) << 1) | (BIT(val,B0) << 0))

typedef unsigned char UINT8;
using namespace std;

int main()
{
static const UINT8 xor_table[128] =
{
0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
0x05,0x55,0x50,0x14,

0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
0x05,0x55,0x50,0x14,0x41,0x45,0x00,0x50,0x54,0x11,0x45,0x40,
0x04,0x54,0x51,0x15,0x40,0x44,0x01,0x51,0x55,0x10,0x44,0x41,
0x05,0x55,0x50,0x14,
};

static const int swap_table[128] =
{
0,0,0,0,
1,1,1,1,1,
2,2,2,2,2,
3,3,3,3,
4,4,4,4,4,
5,5,5,5,5,
6,6,6,6,6,
7,7,7,7,7,
8,8,8,8,
9,9,9,9,9,
10,10,10,10,10,
11,11,11,11,11,
12,12,12,12,12,
13,13,

8,8,8,8,
9,9,9,9,9,
10,10,10,10,10,
11,11,11,11,
12,12,12,12,12,
13,13,13,13,13,
14,14,14,14,14,
15,15,15,15,15,
16,16,16,16,
17,17,17,17,17,
18,18,18,18,18,
19,19,19,19,19,
20,20,20,20,20,
21,21,
};

static const UINT8 swaptable[24][4] =
{
{ 6,4,2,0 }, { 4,6,2,0 }, { 2,4,6,0 }, { 0,4,2,6 },
{ 6,2,4,0 }, { 6,0,2,4 }, { 6,4,0,2 }, { 2,6,4,0 },
{ 4,2,6,0 }, { 4,6,0,2 }, { 6,0,4,2 }, { 0,6,4,2 },
{ 4,0,6,2 }, { 0,4,6,2 }, { 6,2,0,4 }, { 2,6,0,4 },
{ 0,6,2,4 }, { 2,0,6,4 }, { 0,2,6,4 }, { 4,2,0,6 },
{ 2,4,0,6 }, { 4,0,2,6 }, { 2,0,4,6 }, { 0,2,4,6 },
};

char *input, *opcodes, *data;
int long_input, A;

ifstream fichero_input("input", ios::in|ios::binary|ios::ate);
long_input = (int) fichero_input.tellg();
fichero_input.seekg (0, ios::beg);
input = new char [long_input];
opcodes = new char [long_input];
data = new char [long_input];
fichero_input.read (input, long_input);
fichero_input.close();

for (A = 0x0000; A < long_input; A++)
{
int row;
UINT8 src;
const UINT8 *tbl;

src = input[A];

/* pick the translation table from bits 0, 3, 6, 9, 12 and 14 of the address */
row = (A & 1) + (((A >> 3) & 1) << 1) + (((A >> 6) & 1) << 2)
+ (((A >> 9) & 1) << 3) + (((A >> 12) & 1) << 4) + (((A >> 14) & 1) << 5);

/* decode the opcodes */
tbl = swaptable[swap_table[2*row]];
opcodes[A] = BITSWAP8(src,7,tbl[0],5,tbl[1],3,tbl[2],1,tbl[3]) ^ xor_table[2*row];

/* decode the data */
tbl = swaptable[swap_table[2*row+1]];
data[A] = BITSWAP8(src,7,tbl[0],5,tbl[1],3,tbl[2],1,tbl[3]) ^ xor_table[2*row+1];
}

ofstream fichero_opcodes("opcodes", ios::out|ios::binary|ios::trunc);
fichero_opcodes.write (opcodes, long_input);
fichero_opcodes.close();

ofstream fichero_data("data", ios::out|ios::binary|ios::trunc);
fichero_data.write (data, long_input);
fichero_data.close();
};

Como veis, no es más que el trozo correspondiente de fuente de MAME, con una gestión básica de ficheros. En definitiva, tengo un fichero con los opcodes desencriptados y otro con los datos desencriptados.

Si desensamblo el fichero de opcodes, me encuentro con esto al principio:

Código: [Seleccionar]
0000 f3        di     
0001 ed56      im      1
0003 c34c45    jp      454ch

Pues bien, si corro el juego en MAME con el debugger activado, me encuentro esto:

Código: [Seleccionar]
0000 DI F3
0001 IM 1 ED 06
0003 JP $011C C3 1C 01

Esos dos bytes que difieren en la instrucción de salto, los está cogiendo del área de data, no del área de opcodes. ¿Quiere eso decir que, en un área de código, C3 se está interpretando como opcode, pero los dos bytes siguientes se interpretan como datos?

Si es así, estoy jodido y desisto, porque "desentrelazar" esto se escapa de mis posibilidades...

Gracias por vuestra ayuda.

Un saludo.


ArcadeHacker

  • Con experiencia
  • ***
  • Mensajes: 644
  • .
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #1 en: 11 de Julio de 2014, a las 22:22 horas »
Gran proyecto! Yo veo que tu codigo desencriptado es correcto, el que has sacado del mame tiene los datos cifrados, creo que en el debugger del mame hay una opcion para cambiar esto (ver datos cifrados o no), revisa.
Busco placa de Taito: Chack'n Pop.

Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #2 en: 11 de Julio de 2014, a las 23:55 horas »
Gracias por tu comentario, edcross.

Mi duda viene por lo siguiente. Yo entiendo que un opcode como el JP es todo, es decir, el C3, pero también la dirección de salto que le sigue. Por eso entiendo que debería coger los tres bytes del fichero de opcodes desencriptados.

Pues bien, si hago eso, obtengo  jp      454c.

Pero si corro el código en el debugger de MAME, la instrucción que realmente MAME corre es JP    011C. Es decir, MAME está cogiendo el C3 del fichero de opcodes desencriptados, pero la dirección de salto la está sacando del fichero de datos desencriptado.

Como bien dices, el debugger tiene una opción para ver unos u otros.

Lo que me preocupa es que si a la hora de entrelazar tengo que tener en cuenta instrucciones como las de salto absoluto, o las de carga tipo LD A,XX (el XX también parece ir en la parte de datos), me puedo volver loco. Para mi un opcode es todo, incluyendo el valor hexadecimal que marca el valor que hay que cargar en un registro, o la dirección de un salto. En ese caso entrelazar es algo más sencillo. Pero MAME no está haciendo eso, con lo cual deduzco que el 315-5177 tampoco...

Entonces la duda es: cuando el Z80 va a ejecutar una instrucción del tipo JP XXXX, yo supondría que M1 está siempre al mismo nivel. Pero si considera C3 como opcode (M1 a un nivel) y XXXX como datos (M1 al nivel contrario), estoy jodido...

Y ya digo que en la ejecución con el debugger parece que sea así...

¿Tú con el Pang te encontraste con este problema?

Un saludo.


Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #3 en: 11 de Julio de 2014, a las 23:58 horas »
Cita de: edcross en11 de Julio de 2014, a las  22:22 horas
el que has sacado del mame tiene los datos cifrados

No exactamente, tiene los valores que acompañan a las instrucciones (lo que yo pensaba que seguirían siendo opcodes, nunca datos), desencriptados según el patrón de desencriptado de datos...


Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #4 en: 12 de Julio de 2014, a las 00:14 horas »
Por aclarar un poco más. Esas tres instrucciones, en la ROM original aparecen como sigue:

Código: [Seleccionar]
f7
bc 52
92 48 14

Que no significa nada.

Si desencripto según la encriptación OPCODES, obtengo:

Código: [Seleccionar]
0000 f3        di     
0001 ed56      im      1
0003 c34c45    jp      454ch

Que a mi entender debería ser lo correcto, ya que para mi todo eso serían opcodes.

Si desencripto según la encriptación de DATOS, obtengo:

Código: [Seleccionar]
a3
a9 06
87 1c 01

Que tampoco tiene sentido.

Pues bien, si ejecuto el juego en MAME, está ejecutando una mezcla de la desencriptación de OPCODES y de la de DATOS, porque de la primera toma el OPCODE "JP" (C3),  y de la segunda coge la dirección de salto (1C 01).

Un saludo.


ArcadeHacker

  • Con experiencia
  • ***
  • Mensajes: 644
  • .
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #5 en: 12 de Julio de 2014, a las 01:15 horas »
Realmente en el mame la cpu salta a 0x011C ?

En ese caso lo que comentas es correcto pero me llama la atención que la instrucción anterior "ED 56" se esté tomando como 2 opcodes y no opcode + dato.
Busco placa de Taito: Chack'n Pop.

Fortuna

  • Si un Bootleg sirve, se juega igual
  • Recien llegado
  • Mensajes: 52
  • Si hay bootleg, es una reliquia tambien
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #6 en: 12 de Julio de 2014, a las 06:44 horas »
Es extraño, puede que sea un nuevo set, tiene diferentes lecturas comparadas con las del mame, a lo mejor sean de otro set, que en mi pensamiento no lo son

Mi pasatiempo es jugar.
Wishlist: Pengo (pingüino de color azul, bootleg), The punisher, Moon alien o Astrians, Cadillacs & dinosaurs.

Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #7 en: 12 de Julio de 2014, a las 07:27 horas »
Cita de: edcross en12 de Julio de 2014, a las  01:15 horas
Realmente en el mame la cpu salta a 0x011C ?

Sí, se ve claramente al ejecutar el juego paso a paso en el debugger.

Cita de: edcross en12 de Julio de 2014, a las  01:15 horas
En ese caso lo que comentas es correcto pero me llama la atención que la instrucción anterior "ED 56" se esté tomando como 2 opcodes y no opcode + dato.

Pues precisamente a mi me extraña justo lo contrario. ED 56 en teoría es IM 1. Y ambos bytes deberían tomarse del fichero de OPCODES, ya que ambos forman parte de la instrucción (de dos bytes), ¿no? Pues según MAME en realidad se está corriendo la instrucción ED 06. que también se está entendiendo como IM 1 (no sé por qué), tomando el segundo byte del fichero de DATOS, no de OPCODES...

Fortuna, este set es el que ahora mismo está como wboy.zip. Los nombres de los sets van cambiando, así que quizá tú estés revisando otro set llamado wboy.zip más antiguo, que no es como este.

Un saludo.


Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #8 en: 12 de Julio de 2014, a las 07:32 horas »
Vale, estoy viendo el manual del Z80, y realmente entiende el "1" de IM 1 como un operando...

Entonces, por aclarar: para desencriptar una instrucción, del fichero de OPCODES desencriptado debo obtener lo que en el manual viene como Op Code, que no incluye el operando de la instrucción. Por tanto, el operando lo tengo que obtener del fichero de DATOS desencriptado.

Eso hace que ya no estemos hablando de áreas de memoria encriptadas de una manera, y otras áreas de otra, como yo pensaba. Ya estamos hablando de que el entrelazado es brutal, ya que en un área de código tengo que coger en direcciones sucesivas dos o tres bytes de un fichero, dos o tres bytes de otro... Me puedo morir.

Definitivamente, esto a mano no se puede hacer.

Gracias edcross por tu ayuda.

Un saludo.


ArcadeHacker

  • Con experiencia
  • ***
  • Mensajes: 644
  • .
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #9 en: 12 de Julio de 2014, a las 10:57 horas »
Es un trabajo que sin ayuda mecanica es casi imposible. Con el tema del Pang hice cambios en el driver z80 del mame para poder obtener un fichero mascara con las posiciones de opcodes y datos según se van ejecutando, cuanto más juegas más completo es el mapa.

El driver modificado crea un fichero "z80.log" del tamaño de la memoría direccionable en el z80 (65536 bytes) y luego va escribiendo lo siguiente:

FF = cuando se ha leido un opcode
AA = argumento (dato)
22 = lectura de memoria
55 = escritura en memoria

(y tambien AAAA, 2222 y 5555 para argumentos,lecturas,escrituras de 16 bits)

                        case 1: byte8[0] = 0xFF; break; /* op code */
                        case 2: byte8[0] = 0xAA; break; /* op code argument */
                        case 7: byte16[0] = 0xAAAA; break; /* op code argument16 */
                        case 3: byte8[0] = 0x22; break; /* memory read */
                        case 4: byte8[0] = 0x55; break; /* memory write */
                        case 5: byte16[0] = 0x2222;  break; /* memory read16 */
                        case 6: byte16[0] = 0x5555;  break; /* memory write16 */

Ahora... el tema se complica cuando hay roms banqueadas, como es el caso del Pang. Lo es tambien en el wonderboy?

En el caso del pang se trata de dos roms, la principal (0000-7fff) y otra rom banqueada de 128ks divida en 8 partes de 16ks direccionada en 8000-bfff.

Para ello implementé en el driver codigo para detectar los cambios de bancos y y escribir un fichero extra "banked.log" con la rom banqueada reconstruida siguiendo tambien los codigos de arriba (opcode leido, argumento etc..).

En este caso la detección de un cambio de banco se realiza mirando la operación (OUT 0x02, byte) utilizada por la placa de pang para solicitar un cambio de banco. En wonderboy el sistema sera otro con toda seguridad. Estos son los casos que van el byte del OUT 0x02 de pang:

                        case 0: PC = PC - banked_region[0]; break; /* 00000-03fff */
                        case 1: PC = PC - (banked_region[0] /2); break; /* 04000-0bfff */
                        case 2: ; break; /* 8000 - bfff */
                        case 3: PC = PC + (banked_region[0] /2); break; /* 0c000-0ffff */
                        case 4: PC = PC + (banked_region[0]); break; /* 10000-13fff */
                        case 5: PC = PC + (banked_region[0] *1.5); break; /* 14000-17fff */
                        case 6: PC = PC + (banked_region[0] *2);  break; /* 18000-1bfff */
                        case 7: PC = PC + (banked_region[0] *2.5);; break; /* 1c000-1ffff */

Como puedes ver, si el código del pang ejecuta un "OUT 0x02, 0", entonces la placa reacciona colocando el primer bloque de la rom (00000-03fff) en la zona banqueada visible por la cpu (8000-bfff).

Te acabo de enviar el driver al email, tan solo tienes que sustituirlo por el que lva en las fuentes del mame por defecto dentro de "src/emu/cpu/z80/" y compilar.

Al principio del driver verás varias cosas que se pueden cambiar, nombre de los ficheros...direccionamiento y tamaño de la rom banqueada...etc..

Suerte y no dudes en escribir/llamar si tienes cualquier duda!





Busco placa de Taito: Chack'n Pop.

Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #10 en: 12 de Julio de 2014, a las 11:32 horas »
Muchísimas gracias, edcross. Sabía que entrelazar código y datos era difícil, pero no imaginaba cuánto.

Tenía la idea equivocada de que opcodes era todo el área de código, y datos eran, por ejemplo, áreas de memoria donde el Z80 guarda información (por ejemplo gráfica, de sonido, etc.), y que le permitirá dar órdenes. Pero la cosa es mucho más compleja, y realmente cada instrucción lleva su opcode y sus "argumentos", que son los "datos". En el caso de los sistemas System16B sí era como yo decía, pero aquí es infinitamente más complejo.

No, este Wonder Boy no lleva bancos, así que será más fácil que en el caso del Pang.

Trataré de liarme gracias a la información que me pasas.

De nuevo muchas gracias.

Un saludo.


ArcadeHacker

  • Con experiencia
  • ***
  • Mensajes: 644
  • .
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #11 en: 13 de Julio de 2014, a las 17:01 horas »
Buenas, solo confirmarte que el caso de IM XX son dos opcodes y no opcode + dato. Hoy me acorde que tambien tuve esta confusión al comenzar con el proyecto del pang.
Busco placa de Taito: Chack'n Pop.

Marcos75

  • ****
  • Mensajes: 3042
  • Arcadero de los 80s
Re:Desencriptar WONDER BOY (set 1, 315-5177)
« Respuesta #12 en: 13 de Julio de 2014, a las 18:53 horas »
Gracias edcross. La verdad es que eso es lo lógico, pero me despistó porque si en el debugger de MAME cambias entre opcodes raw y decrypted, ese segundo byte SÍ cambia como si fuese un dato...

De momento, y mientras me animo a tratar de entrelazar código y datos, he grabado memorias del doble de tamaño, con los opcodes abajo y los datos arriba (tipo Pang! o Wonder Boy in Monsterland), y funciona bien seleccionando entre los dos bloques con la señal /M1.

Un saludo.