Hola!!!
Tienes una idea? Quieres hacer una herramienta pero no sabes como? Si? Pues que raro, no es que sea muy frecuente, lol
Ok, ya he acabado mi chiste malo, ahora viene la intro del tutorial.
Bueno, en este tutorial vamos a aprender a leer y modificar un ROM usando python, lo que nos permite crear herramientas en un lenguaje fácil de aprender como es python.
En este tutorial no aprenderemos python. Este tutorial está orientado a gente que ya sabe un poco de python, pero no sabe como escribir bytes en un rom.
Dificultad: Baja (Voy a poner ejemplos), si sabes python. Si conoces otros lenguajes de programación como C, java, o similares (HTML NO es un lenguaje de programación xD), sería media-baja, si nunca has programado pero eres inteligente, deberías poder entenderlo, y si no eres tan listo, pues ejem, piensa, luego busca en google y finalmente pregunta, ok?
Ok, empezamos:
Leer y modificar un rom con python
NOTA: Todas las lineas que empiecen con import, solo hay que ponerlas una vez en todo el programa. Recomiendo escribirlos todos al principio.
Leer el rom:
Primero vamos a definir una variable que contendrá la ruta hasta el ROM:
El nombre del rom, o la ruta completa hasta el rom
ejemplo1: filename = "mirom.gba"
ejemplo2 (linux): filename = "/home/mi_usuario/asdf/mirom.gba"
ejemplo3 (windows): filename = "C:\Users\usuario\asdf\mirom.gba"
Luego abrimos el rom
f es el nombre de la variable que almacenará el la función open(), open es la función que abre el rom, filename es la variable que hemos definido antes y "rb" es la opción de leer bytes (r,read, y b,bytes).
Luego almacenamos lo que el contenido del rom en una variable.
fcontents es la variable donde almacenamos todos los bytes del rom. (Va a ser de tipo string)
Si estás abriendo un ROM real y haces un "print fcontents" vas a morir (o tu PC va a morir), porque se escribirá todo el contenido del rom en tu terminal
Si en lugar de un ROM de GBA estas usando un binario creado por ti en un editor HEX, puedes imprimirlo en pantalla de dos maneras diferentes:
1:
Si tu binario contiene 0011223344, va a escribir:
'\x00\x11"3D'
2:
Si tu binario contiene 0011223344, va a escribir:
0011223344
NOTA: A partir de ahora, para decir "imprimir en pantalla" usaré el verbo inexistente "printar", que es mas corto
Ok, ahora vamos a printar el byte que hay en un offset (decimal) en concreto:
Ahora lo mismo usando un offset HEX:
Y ahora vamos a printar de un offset (HEX) a otro
NOTA: El primero tiene que ser un numero mas
pequeño que el segundo (lógico, no?)
Modificar el rom (escribir):
Necesitamos el texto que hay en el ROM, así que si no lo hemos hecho:
Escribir un solo byte (algo así como el WBTO pero para el ROM xD):
Escribir tantos bytes como queramos
Ya hemos acabado, pero si has llegado hasta aquí leyéndolo todo, te agradecería que me dejaras un mensaje en el perfil con tu opinión y, si las tienes, dudas.
Espero que ayude a la gente a crear sus herramientas
Bye!
EDIT 7: He añadido muchos ejemplos y explicaciones
EDIT 8: He añadido MÁS ejemplos y explicaciones.
Tienes una idea? Quieres hacer una herramienta pero no sabes como? Si? Pues que raro, no es que sea muy frecuente, lol
Ok, ya he acabado mi chiste malo, ahora viene la intro del tutorial.
Bueno, en este tutorial vamos a aprender a leer y modificar un ROM usando python, lo que nos permite crear herramientas en un lenguaje fácil de aprender como es python.
Bueno, yo solo diré que para escribir en un rom de 16 MB (pokemon ruby) ha tardado tan poco que ni me he enterado que ya lo había hecho (Si, mucho menos de un segundo), y que el python es mucho mas fácil
En este tutorial no aprenderemos python. Este tutorial está orientado a gente que ya sabe un poco de python, pero no sabe como escribir bytes en un rom.
Dificultad: Baja (Voy a poner ejemplos), si sabes python. Si conoces otros lenguajes de programación como C, java, o similares (HTML NO es un lenguaje de programación xD), sería media-baja, si nunca has programado pero eres inteligente, deberías poder entenderlo, y si no eres tan listo, pues ejem, piensa, luego busca en google y finalmente pregunta, ok?
Ok, empezamos:
Leer y modificar un rom con python
NOTA: Todas las lineas que empiecen con import, solo hay que ponerlas una vez en todo el programa. Recomiendo escribirlos todos al principio.
Leer el rom:
Primero vamos a definir una variable que contendrá la ruta hasta el ROM:
Código:
filename = ""
ejemplo1: filename = "mirom.gba"
ejemplo2 (linux): filename = "/home/mi_usuario/asdf/mirom.gba"
ejemplo3 (windows): filename = "C:\Users\usuario\asdf\mirom.gba"
Luego abrimos el rom
Código:
f = open(filename, "rb")
Luego almacenamos lo que el contenido del rom en una variable.
Código:
fcontents = f.read()
Para evitar problemas (y ahorrar RAM), recomiendo cerrar ya el archivo con un f.close() , porque al haber copiado todo su contenido en fcontents, ya no lo necesitamos mas.
Si estás abriendo un ROM real y haces un "print fcontents" vas a morir (o tu PC va a morir), porque se escribirá todo el contenido del rom en tu terminal
Si en lugar de un ROM de GBA estas usando un binario creado por ti en un editor HEX, puedes imprimirlo en pantalla de dos maneras diferentes:
1:
Código:
print fcontents
'\x00\x11"3D'
En este momento, fcontents contiene datos en hex, así que al mostrarlo en pantalla, los que pueda (como ", 3 y D), los va a mostrar con su equivalente en ascii.
La tabla es esta: tabla
La tabla es esta: tabla
2:
Código:
import binascii
print binascii.hexlify(fcontents)
0011223344
Esto es lo mismo que el anterior, con la diferencia que formateamos el texto para que aparezca así: "0011223344", usando la función hexlify del modulo binascii, de esta manera:
Código:
binascii.hexlify(variable_a_codificar)
NOTA: A partir de ahora, para decir "imprimir en pantalla" usaré el verbo inexistente "printar", que es mas corto
Ok, ahora vamos a printar el byte que hay en un offset (decimal) en concreto:
Código:
offsetdec = "123456"
Donde 123456 es el offset DECIMAL del byte a printar. Si quisiéramos ver lo que hay en offset 100000, escribiríamos:
Código:
offsetdec = "100000"
Código:
import binascii
print binascii.hexlify(fcontents[offsetdec])
Recordad que si ya lo hemos hecho antes, no hace falta importar binascii, pero no pasa nada por hacerlo 2 veces ;D.
Otra manera mas larga (pero también más entendible) de escribirlo sería:
Otra manera mas larga (pero también más entendible) de escribirlo sería:
Código:
nuestro_byte_binario = fcontents[offsetdec] # almacenamos nuestro byte en una variable
nuestro_byte_leible = binascii.hexlify(nuestro_byte_binario) # Lo almacenamos en otra convertido
print nuestro_byte_leible # Lo escribimos
Para entender como cogemos el byte de fcontents (la parte de "fcontents[offsetdec]"):
Siempre que ponemos un numero entre "[]" al lado del nombre de una variable, nos estamos refiriendo a una posición dentro de esta.
Por ejemplo:
Nos escribiría en pantalla:
Siempre que ponemos un numero entre "[]" al lado del nombre de una variable, nos estamos refiriendo a una posición dentro de esta.
Por ejemplo:
Código:
variable = "asdfghjkl"
print variable[0]
print variable[1]
print variable[2]
print variable[2] + variable[1] + variable[0]
Código:
a
s
d
dsa
Ahora lo mismo usando un offset HEX:
Código:
offsethex = "123456"
Donde 123456 es el offset HEXADECIMAL del byte a printar. Si quisiéramos ver lo que hay en offset 800000, escribiríamos:
Código:
offsetdec = "800000"
Código:
import binascii
print binascii.hexlify(fcontents[int(offsethex, 16)])
Es igual que el anterior, con la diferencia que usamos un offset HEX, que convertimos a decimal con la función "int(offsethex, 16)"
Ejemplo:
Este programa:
que es lo mismo que esto:
Nos imprimiría en pantalla esto:
Ejemplo:
Este programa:
Código:
variable = "asdfghjklzxcvbnm"
offsethex = "C"
print variable[int(offsethex, 16)]
Código:
variable = "asdfghjklzxcvbnm"
offsethex = "C"
offset_convertido = int(offsethex, 16)
print variable[offset_convertido]
Código:
v
Y ahora vamos a printar de un offset (HEX) a otro
Código:
offsethex1 = "800000"
offsethex2 = "800100"
Donde 800000 es el offset hex del primer byte a printar, y 800100 el del último.
NOTA: El primero tiene que ser un numero mas
pequeño que el segundo (lógico, no?)
Código:
import binascii
print binascii.hexlify(fcontents[int(offsethex1, 16):int(offsethex2, 16)])
Pongo un ejemplo y seguro que lo entendéis:
Este programa:
Nos daría esto:
No lo has entendido? Bueno, lo explico.
Si habéis leído todas las explicaciones que llevamos hasta ahora, ya sabréis que el numero entre "[" y "]" nos indica una posición dentro de la variable que tiene a su izquierda. Si no, leedlo.
Bueno, pues si en lugar de un numero ponemos 2 separados por dos puntos (":"), nos estamos refiriendo a todo lo que hay entre el primero y el último. Como me explico mal, pongo más ejemplos:
Daría esto:
Si nos pasamos, como en:
Se escribe hasta el final.
Por si alguien va MUY perdido, lol:
En python, cualquier cosa se puede sustituir por una variable que lo contenga, siendo lo mismo
que
Este programa:
Código:
variable = "asdfghjklzxcvbnm"
offsethex1 = "1"
offsethex2 = "C"
offset_convertido1 = int(offsethex1, 16)
offset_convertido2 = int(offsethex2, 16)
print variable[offset_convertido1:offset_convertido2]
Código:
sdfghjklzxc
Si habéis leído todas las explicaciones que llevamos hasta ahora, ya sabréis que el numero entre "[" y "]" nos indica una posición dentro de la variable que tiene a su izquierda. Si no, leedlo.
Bueno, pues si en lugar de un numero ponemos 2 separados por dos puntos (":"), nos estamos refiriendo a todo lo que hay entre el primero y el último. Como me explico mal, pongo más ejemplos:
Código:
var = "buenos dias :D"
print var
print var[0:20]
print var[0:5]
print var[2:4]
Código:
buenos dias :D
buenos dias :D
bueno
en
Código:
print var[0:20]
Por si alguien va MUY perdido, lol:
En python, cualquier cosa se puede sustituir por una variable que lo contenga, siendo lo mismo
Código:
print "hola"
Código:
variable = "hola"
print variable
Modificar el rom (escribir):
Necesitamos el texto que hay en el ROM, así que si no lo hemos hecho:
Código:
filename = "Ruby.gba"
Donde Ruby.gba es la ruta hasta el ROM.
Ejemplos:
El nombre del rom, o la ruta completa hasta el rom
ejemplo1: filename = "mirom.gba"
ejemplo2 (linux): filename = "/home/mi_usuario/asdf/mirom.gba"
ejemplo3 (windows): filename = "C:\Users\usuario\asdf\mirom.gba"
Ejemplos:
El nombre del rom, o la ruta completa hasta el rom
ejemplo1: filename = "mirom.gba"
ejemplo2 (linux): filename = "/home/mi_usuario/asdf/mirom.gba"
ejemplo3 (windows): filename = "C:\Users\usuario\asdf\mirom.gba"
Código:
f = open(filename, "rb")
fcontents = f.read()
Esto está explicado más arriba, ok?
Escribir un solo byte (algo así como el WBTO pero para el ROM xD):
Código:
fwb = open(filename, "wb")
Volvemos a abrir el ROM, esta vez en modo de escritura.
Código:
newbyte = "2C"
Donde 2C es el byte en HEX a insertar.
Código:
hexoffset = "800500"
Donde 800500 es el offset donde insertaremos el byte (en hex).
Código:
import binascii
fwb.write(fcontents[:int(hexoffset, 16)] + binascii.a2b_hex(newbyte) \
+ fcontents[int(hexoffset, 16) + 1:])
La backslash ("\"), se usa para anular al cambio de linea, con lo que es lo mismo escribir:
que
Código:
asdf = "123"
Código:
asdf = \
"123"
Esto es lo difícil:
Vamos a hacerlo poco a poco:
Lo que haremos será escribir en el rom, que hemos abierto en modo de escritura en la var "fwb", así que:
Ahora lo llenamos con lo que queremos escribir
Lo sustituimos por algo mas parecido al resultado final
Y en realidad la variable no se llama ROM, sino dcontents, así que lo cambiamos:
Ahora codificamos los offsets y el byte.
Y bueno, este es el resultado final:
Pero para hacerlo mas fácil también se podría escribir así:
Código:
fwb.write(fcontents[:int(hexoffset, 16)] + binascii.a2b_hex(newbyte) \
+ fcontents[int(hexoffset, 16) + 1:])
Vamos a hacerlo poco a poco:
Lo que haremos será escribir en el rom, que hemos abierto en modo de escritura en la var "fwb", así que:
Código:
fwb.write()
Código:
fwb.write(inicio_del_rom + bytes + final_del_rom)
Código:
fwb.write(ROM[:offset] + bytes + ROM[offset + 1:])
"ROM[ffset]" significa, des del principio del ROM hasta el offset, y "ROM[offset:]" significa des del offset hasta el final del ROM. Si lo hiciéramos así, estaríamos añadiendo un byte al ROM y se nos desplazaría todo dejandolo inservible, por lo que en lugar de "ROM[offset:]" hacemos un "ROM[offset + 1:]", que escribe des de un byte (el que hemos escrito) después del offset hasta el final.
Y en realidad la variable no se llama ROM, sino dcontents, así que lo cambiamos:
Código:
fwb.write(fcontents[:offset] + bytes + fcontents[offset + 1:])
Código:
fwb.write(fcontents[:int(hexoffset, 16)] + binascii.a2b_hex(newbyte) \
+ fcontents[int(hexoffset, 16) + 1:])
Código:
fwb.write(fcontents[:int(hexoffset, 16)] + binascii.a2b_hex(newbyte) \
+ fcontents[int(hexoffset, 16) + 1:])
Código:
offset = int(hexoffset, 16)
inicio_del_rom = fcontents[:offset]
final_del_rom = fcontents[offset + 1:]
byte_codificado = binascii.a2b_hex(newbyte)
newcontent = inicio_del_rom + byte_codificado + final_del_rom
fwb.write(newcontent)
Escribir tantos bytes como queramos
Código:
fwb = open(filename, "wb")
newbytes = "3322446655AA00FFDD"
Donde "3322446655AA00FFDD" son los bytes que vamos a escribir.
Código:
hexoffset = "800000"
Donde "800000" Es el offset donde vamos a insertar los bytes
Código:
import binascii
fwb.write(fcontents[:int(hexoffset, 16)] + binascii.a2b_hex(newbytes) \
+ fcontents[int(hexoffset, 16) + len(binascii.a2b_hex(newbytes)):])
En este tenemos lo mismo que en el anterior con solo 2 pequeños cambios:
1 - En lugar de escribir un byte codificado escribimos varios
2 - Como escribimos varios, en lugar de desplazar el offset en el que empieza el final del ROM 1 byte, lo desplazamos la longitud de nuestra cadena de bytes, que calculamos con "len()"
Separado sería:
1 - En lugar de escribir un byte codificado escribimos varios
2 - Como escribimos varios, en lugar de desplazar el offset en el que empieza el final del ROM 1 byte, lo desplazamos la longitud de nuestra cadena de bytes, que calculamos con "len()"
Separado sería:
Código:
offset = int(hexoffset, 16)]
principio_rom = fcontents[:offset]
bytes_conv = binascii.a2b_hex(newbytes)
longitud_newbytes = len(bytes_conv)
final_rom = fcontents[offset + longitud_newbytes:]
contenido_modif = principio_rom + bytes_conv + final_rom
fwb.write(contenido_modif)
Ya hemos acabado, pero si has llegado hasta aquí leyéndolo todo, te agradecería que me dejaras un mensaje en el perfil con tu opinión y, si las tienes, dudas.
Espero que ayude a la gente a crear sus herramientas
Bye!
EDIT: Código en colores (pero sin acentos) aquí: http://cosarara97.x10.mx/files/pythontuts/pythonROMs1.html
EDIT 2: Adjunto tenéis el código en un txt con tabulaciones, y si teneis un buen editor de textos para programar lo podéis renombrar a *.py para tener colores
EDIT 3: Había un error en el tutorial, que ya se ha corregido en el post pero aún no el la versión coloreada (el link) ni el adjunto. Cuando pueda lo corrijo, mientras leed del post :/
EDIT 4: El adjunto ya está arreglado
EDIT 5: Dejo como adjunto un programa (un poco chapucero) para la linea de comandos como ejemplo, os recomiendo usarlo un poco y leer el código después de leer el tutorial para tener un ejemplo práctico.
EDIT 6: He hecho otra versión del programa más elegante, está adjunta.
EDIT 2: Adjunto tenéis el código en un txt con tabulaciones, y si teneis un buen editor de textos para programar lo podéis renombrar a *.py para tener colores
EDIT 3: Había un error en el tutorial, que ya se ha corregido en el post pero aún no el la versión coloreada (el link) ni el adjunto. Cuando pueda lo corrijo, mientras leed del post :/
EDIT 4: El adjunto ya está arreglado
EDIT 5: Dejo como adjunto un programa (un poco chapucero) para la linea de comandos como ejemplo, os recomiendo usarlo un poco y leer el código después de leer el tutorial para tener un ejemplo práctico.
EDIT 6: He hecho otra versión del programa más elegante, está adjunta.
EDIT 7: He añadido muchos ejemplos y explicaciones
EDIT 8: He añadido MÁS ejemplos y explicaciones.