tuts_gba
Thread Id: 16901
Thread Name: GBA | Otros | Arreglando el ROM con cosarara97
#0
cosarara97 12296
En html: https://www.dropbox.com/s/j5l6zshp7fyh1or/tut.html
En markdown: https://www.dropbox.com/s/5dmrccofavuzqqf/tut.md (la fuente para el html)
El IPS que creé al arreglar el Terra Firma de Rata: TF_fix.ips (no contiene el hack).

El tutorial está pensado para ser seguido desde linux, pero también deberíais poder seguirlo (más o menos) desde windows, si sois listos. Saber usar la linea de comandos es indispensable.

PD: No le he pasado el corrector ortográfico.

Arreglando el ROM
Tutorial escrito por cosarara97. CC-BY-NC
Corrompiendo un ROM (lol)
Nota: (Obviamente esta parte no es necesaria si ya tenemos un ROM roto que queremos arreglar)
Pues eso, que cuando me he puesto a escribir el tuto me he encontrado con queno tenía ningún ROM roto con el que hacerlo. Así que he roto uno.Tenía era un IPS que le hice a Rata una vez que le arreglé el ROM, así que loúnico que he tenido que hacer ha sido mirar que bytes tocaba ese IPS yponerlos a 00 en un ROM limpio (pues en ese ROM de Rata los bytes malosestaban en 00).
Esta creo que es la parte más divertida del tuto :D
Creamos un ROM en blanco (en cero, en realidad):
$ dd if=/dev/zero of=dummy.gba bs=16777216 count=1

Hacemos una copia:
$ cp dummy.gba dummy_patch.gba

Aplicamos el parche:
$ ./uips a TF_fix.ips dummy_patch.gba

Comparamos el ROM parcheado y el sin parchear, guardamos los offsets condiferencias en un archivo llamado "log":
$ cmp -l dummy.gba dummy_patch.gba | awk '{printf "%08X\n", $1}' > log

Usamos un simpático script que he escrito especialmente para la ocasión (?):
$ python break_rom.py log
opening gastric juice file...
Program: ROMs ROMs ROMs!!! I like to eat ROMs!!!
Feed the Program a ROM? [y/N]: y
program: Yay!
Path to ROM: to_break.gba
*program is eating*
*program finished eating*
saving shit to "to_break.gba.broken" ...

(podeis encontrar el script al final del tutorial)
Renombramos el ROM roto:
$ mv to_break.gba.broken to_break.gba.broken.gba

Y ya está :)
Consiguiendo el trace.log
Bien, tenemos nuestro increíble ROM roto aquí al lado, lo abrimos conVBA-SDL-H y empieza la magia:
$ ./VBA-SDL-H --save-flash --flash-128k to_break.gba.broken.gba

Ejecutamos el ROM, vamos hasta justo antes del bug y guardamos (savestate y/o guardado normal, lo que te sea más cómodo).
Bien, ahora, toqueteando un poco los argumentos del emulador es posible que pudieramos hacer que el juego fuera más lento, pero como soy muy vago paso de hacerlo.
Bien, ahora que estamos a punto de llegar al bug (metiéndonos en la hierba,metiéndonos en un menú, yo qué sé), le damos al F11. Whoha!, se ha parado!
Sí, se ha parado, pero aún hay más, en el terminal se ha abierto el debugger.
Podemos aprender a usar el debugger leyendo el manual de VBA-SDL-H, y ver un listado de los comandos con el comando "h".
Bien, aquí tenemos muchísimas cosas útiles que nos podrían servir, pero vamos a hacerlo fácil y usar algo muy simple: una "trace" (se podría traducira traza o rastro, pero vamos a usar la palabra en inglés).
Que es una trace? Bueno, pues en este caso es una simple lista con las instrucciones que va ejecutando la CPU.
Como no queremos mucha información, primero dejaremos el nivel de debugginga 1:
debugger> strace 1

Ahora vamos a decirle que empiece a escribir la trace (aún así no va aescribir nada hasta que le digamos que continúe la emulación)
debugger> trace start

Y ahora finalmente continuamos la emulación:
debugger> c

Bien, ya has llegado finalmente al bug? (Se ha parado, reiniciado, lo quesea?) Pues pulsa inmediatamente F11 otra vez, si no quieres una trace immensa. A veces el emulador con el tracing activo es jodidamente lento.
Ya otra vez en el debugger, le decimos que pare la trace:
debugger> trace stop

Y salimos:
debugger> q
Are you sure you want to quit (y/n)? y

A veces a este emulador no le da la gana de salir. Si nos pasa (como me acaba de pasar a mi ahora mismo), lo matamos des de otro terminal:
$ killall -9 VBA-SDL-H

Analizando la trace
Bien! ya tenemos la trace! Sí, es ese archivo "trace.log" que tienes ahí.Podríamos haber hecho que se guardara con otro nombre con:
debugger> trace file <nombre>

Pero no hace falta.
No lo abras aún. Primero vamos a ver cuanto pesa :P
El mio pesa 5 increíbles MB. No es mucho, pero es suficiente para que no les guste a mucho editores con interfaz gráfica. Dependiendo de cómo, estas traces pueden llegar a pesar más de 100 MB.
Vamos a ver cuantas instrucciones hemos registrado (cuantas lineas tiene el archibo):
$ wc -l trace.log

El mio tiene 22505 lineas
Vamos a ser super cools y cortarlo en trocitos de un tamaño más humano.
$ mkdir trace
$ cp trace.log trace/
$ cd trace
$ split -l 5000 trace.log

Yay! Solo 5 partes de 1.2MB más o menos, cada una:
$ ls -lh
total 11M
-rw-r--r-- 1 jaume users 5,1M 3 des 19:00 trace.log
-rw-r--r-- 1 jaume users 1,2M 3 des 19:00 xaa
-rw-r--r-- 1 jaume users 1,1M 3 des 19:00 xab
-rw-r--r-- 1 jaume users 1,2M 3 des 19:00 xac
-rw-r--r-- 1 jaume users 1,2M 3 des 19:00 xad
-rw-r--r-- 1 jaume users 590K 3 des 19:00 xae

(Sí, split pone esos nombres raros)
Abro la segunda, usamos la opción -S porque las líneas son muy largas y el final no nos interesa:
$ less -S xa00=03007db4 R01=00000000 R0
0803D2F2 4645 mov r5, r8 R00=03007db4 R01=0000000
0803D2F4 b4e0 push {r5-r7} R00=03007db4 R01=0000000
0803D2F6 1c07 add r7, r0, #0x0 R00=03007db4 R01=0000000
0803D2F8 468a mov r10, r1 R00=03007db4 R01=0000000
0803D2FA 1c14 add r4, r2, #0x0 R00=03007db4 R01=0000000
0803D2FC 2000 mov r0, #0x0 R00=03007db4 R01=0000000
0803D2FE 4680 mov r8, r0 R00=00000000 R01=0000000
...

Muy normal, hasta aquí.
Abrimos el último:
08034078 00000000 andeq r0, r0, r0 R00=00000004 R01=081faf5
0803407C 00000000 andeq r0, r0, r0 R00=00000004 R01=081faf5
08034080 00000000 andeq r0, r0, r0 R00=00000004 R01=081faf5
08034084 21000000 tstcs r0, r0 R00=00000004 R01=081faf5
08034088 00000000 andeq r0, r0, r0 R00=00000004 R01=081faf5
0803408C 00000000 andeq r0, r0, r0 R00=00000004 R01=081faf5
...

No hay que ser un experto para deducir que ya no estamos leyendo lo que deberíamos (en este caso, todo 00s excepto ese 21).
Bien, vamos a mirar en el penúltimo... (si, los estoy eligiendo un poco como quiero, podríamos haber empezado por el 3º, también):
080441EA 3c01 sub r4, #0x1 R00=02000020 R01=060103e
080441EC 2c00 cmp r4, #0x0 R00=02000020 R01=060103e
080441EE d1f2 bne $080441d6 R00=02000020 R01=060103e
...

Todo bien? Pues bingo, en esta parte está el problema. En este caso específico ya deberíamos haber deducido que alrededor de 0x034078 el ROM está corrupto,pero como en otros casos no es así (porque se lee de partes correctas pero delas que no se debería leer, como datos) voy a seguir explicando.
Podríamos volver a partir este archivo en partes, pero me limito a mantener pulsado Page Down hasta que encuentro el punto donde llegamos a los ceros.
08032B2A f1ad bl $081e082c R00=08033525 R01=081faf5
08032B2C fe7f blh $0cfe R00=08033525 R01=081faf5

[last: 081E082C]
08033524 0000 lsl r0, r0, #0x00 R00=08033525 R01=081faf5
08033526 0000 lsl r0, r0, #0x00 R00=08033525 R01=081faf5

Lo que hay de 08032B2C hacia arriba parece bastante normal, no? Si cogieramos un ROM limpio encontraríamos lo mismo. Bueno, pues ya estamos.
Abrimos 2 veces un editor hexadecimal. En una ventana abrimos un ROM limpio,y en la otra el ROM roto. Con las 2 vamos hasta el offset del bug.
Hacemos copy paste del ROM limpio al roto de la parte donde está el bug, y ya está.
El script que digiere los ROMs :)
#!/usr/bin/python3

# Instruction file generated with:
# $ cmp -l dummy dummy_patched | awk '{printf "%08X\n", $1}'

import argparse
parser = argparse.ArgumentParser(description="Eats ROMs.")
parser.add_argument("instructions", metavar="Gastric_acid",
help="The gastric juice for this monster's stomach")
args = parser.parse_args()
print("opening gastric juice file...")
try:
fi = open(args.instructions, "r")
fi_contents = fi.read()
fi.close()
except Exception as e:
print("couldn't read file...")
print(e)
quit(2)

print("Program: ROMs ROMs ROMs!!! I like to eat ROMs!!!")
while True:
a = input("Feed the Program a ROM? [y/N]: ")
if a in "yesYesnoNo":
break
else:
print("yes or no?")

if a in "yesYes" and a:
print("program: Yay!")
else:
print("ok :(")
quit(1)

while True:
fn = input("Path to ROM: ")
try:
f = open(fn, "rb")
f_contents = f.read()
f.close()
break
except:
print("You did something wrong...")

print("*program is eating*")
instructions = fi_contents.split("\n")
ROM = bytearray(f_contents)
for line in instructions:
if not line:
continue
offset = line
ioffset = int(offset, 16)
ROM[ioffset] = 0 # lol, erased the byte :D
print("*program finished eating*")
print("saving shit to \"" + fn + ".broken\" ...")
fw = open(fn + ".broken", "wb")
fw.write(ROM)
fw.close()
#1
Ángel Uchiha 12304
Gracias a ti y tus arreglos, sigo con el islas doradas...
Gracias cosita.
#2
cosarara97 12296
Iniciado por Ángel Asakura
Gracias a ti y tus arreglos, sigo con el islas doradas...
Gracias cosita.


De nada, angelito.
He convertido el tuto a BBcode.
#3
Calzifer 20512
wow, jamas habia visto tanto texto que yo no entienda, en serio en eso de comandos soy reeemalo...
pero bueno esta bueno el tuto, creo yo de lo que puedo ver esta bn explicado, y creo que si, ayuda a muchos que trabajan el hackeo y todo eso... e fin buen tuto...

Suerte¡¡

att.Yo
#4
Elpollo 25323
Parece un buen tuto, pero prefiero el No$GBA Debugger para ver los fallos :)
#5
cosarara97 12296
He rescatado, corregido un poco y resubido las versiones en markdown y html, esta vez a dropbox.
Dropbox te enseña la versión markdown renderizada (that is, en bonito), aunque bueno, ahora ya está todo en el post.
No he probado nunca ese No$GBA Debugger, a ver si un día me lo miro ;).