Hacking Pokemon

Como he comentado en un artículo anterior los pokemons que aparecen en la zona de hierba se almacenan en la posición de la RAM 0xD887 y estos datos ocupan 21 bytes, 1 para la frecuencia de combate y otros 20 bytes para los pokemons que pueden aparecer y sus respectivos niveles. Ocurre lo mismo con los pokemons que aparecen en las zonas de agua, solo que esta información está almacenada en la dirección de la RAM 0xD8A4.

Vamos a probar a modificar estos datos, vamos a establecer que aparezca el pokemon con índice interno 0x15 y con nivel 100 (0x64).

n007

El pokemon con índice interno 0x15 es Mew.

n008

Vamos a cambiar ahora el nombre de nuestro jugador en tiempo de ejecución. Como he dicho en otro artículo el nombre del personaje se almacena en la dirección de la RAM 0xD158

c001

Ahora vamos a cambiar el nombre de ASH por ANGEL LUIS, según el artículo sobre códificación de cadena de textos, la cadena ANGEL LUIS se codifica como 0x80 0x8D 0x86 0x84 0x8B 0x7F 0x8B 0x94 0x88 0x92

n009

Podemos ver como se ha cambiado, estableciendo una longitud en principio no válida por el juego ya que no cabe dentro del menú.

Por último vamos a cambiar el nombre de algún pokemon para ponerle lo que queramos. El nombre de los pokemons está almacenado en la ROM y empieza en la dirección 0x1c21e y respetan el orden según el indice interno de pokemon, es decir, el pokemon que aparece en la primera posición no es bulbasaur sino Rhydorn.

Cada una de estos nombres tiene una longitud de 10 bytes, vamos a cambiar el nombre a Mew que como hemos visto tiene el índice interno 0x15, por tanto desde la dirección 0x1C21E tenemos que contar 0x14 * 0xA = 0xC8 (es 0x14 porque Mew es el numero 0x15 contando desde 0x01, pero aquí estamos considerando que el pokemon con indice 0x01 va a aparecer en el offset 0x00 desde la dirección 0x1C21E, por tanto Mew estará en la posición 0x15-0x01 = 0x14), por tanto el nombre de Mew debe comenzar en la dirección 0x1c2E6

n010

Si lo cambiamos ahora por mi nombre codificado en su sistema, quedará:

n011

Si ahora guardamos la rom y la ejecutamos con el emulador podremos ver lo siguiente:

n012n013

Emulación de una CPU

Hacia ya tiempo que tenía en mente desarrollar un procesador por software, de hecho los primeros ficheros que tengo sobre este proyecto y la documentación datan de 2009-2010, pero debido a que es un proyecto al que hay que dedicarle bastante tiempo lo fui dejando de lado.

Este año me propuse ir desarrollandolo poco a poco a modo de pasatiempo en mis vacaciones, pero al final el ansia por ver almenos algo básico funcionando ha conseguido que me ponga a desarrollarlo antes de tiempo.

En esta entrada voy a enseñar algunas características y explicar algunos aspectos del proyecto.

Para empezar, el procesador no es mi objetivo, mi objetivo es un poco más ambicioso, es desarrollar un sistema completo con RAM, ROM, CPU y GPU.

La CPU, que es lo que viene al caso en esta entrada, es de 8 bits, capaz de direccionar hasta 16KB de memoria RAM que y tiene un juego de instrucciones de 512 instrucciones que se dividen en 256 instrucciones base y 256 instrucciones extendidas. Actualmente tengo implementadas las 256 instrucciones del juego base.

El procesador consta de 7 registros básicos de 8 bits más uno de flags. Estos registros se pueden unir para formar registros de 16 bits. A parte de estos registros tiene otros 2 de uso específico, el PC (Program Counter) y el SP (Stack Pointer) de 16 bits cada uno.

La fase de busqueda, decodificación y ejecución no tienen mucho misterio

bOps es un array de punteros a funcion.

En principio quería avanzar en la CPU propiamente dicha pero conforme iba terminando me di cuenta que necesitaría también un módulo debug (al estilo gdb) para poder probar a fondo el funcionamiento de la CPU.

Para poder hacer pruebas he tenido que crear una memoria con un esquema que no es el que yo quería pero para comprobar el correcto funcionamiento de la CPU es suficiente, esta memoria es de 1KB y se divide de la siguiente forma:

  • 0x00 - 0xFF (256 bytes): En estas posiciones se encuentra el bootloader, aunque ocupa bastante menos que 256 bytes.
  • 0x100 - 0x1FF (256 bytes): Memoria para código. Tras arrancar la CPU el bootloader salta a la posición 0x100 donde se carga el código de programa.
  • 0x200 - 0x3FF (512 bytes): Memoria RAM. Dentro de la memoria RAM cabe destacar la pila que es inicializada a 0x3FF y que va decreciendo conforme se van introduciendo datos en la misma.

Con todo esto ya estaban todos los elementos "hardware", faltan los elementos software, esto es el bootloader y un programa para testear el funcionamiento de la CPU.

No tengo compilador ni traductor para la CPU así que en vez de programar en ensamblador, he tenido que programarlo directamente en código máquina.

El bootloader simplemente inicializar una serie de registros y prepara al procesador para dar el salto a la memoria de código.

El bootloader se establece directamente en la creación de la memoria.

Con el bootloader listo ya somo capaces de dar el salto a la memoria de instrucciones, así que el último elemento que queda es un programa que ejecutar. He optado por un programa sencillo que simplemente implementa el algoritmo de la multiplicación. Al igual que el bootloader al no tener ni compilador ni traductor no he podido usar ensamblador y por tanto lo he escrito en código máquina.

Esta vez si, el programa se encuentra en un fichero a parte, y que se llama mult4x4. El código del programa (en código máquina) es:

El programa multiplica 3 por 3, y escribe en la RAM una cadena con el resultado (pasado a ascii), concretamente escribe "El resultado es: 9". También coloca el registro bc en la pila para después recuperarlo en de.

Con todo esto ya podemos ver en funcionamiento la CPU.

No descarto hacer un traductor de ensamblador a código máquina, total ya he tenido que hacer un desensamblador para el depurador. Aún así, cuando se estudia completamente un procesador, no es muy traumático escribir código máquina directamente.

Unas capturas de pantalla del programa, el bootloader, el diseño del código fuente y un ejemplo del depurador.

El código fuente lo subiré a github en breve.

1 2 3 4 5 6

GZIP y SSL en servicios Web

Al desarrollar un servicio REST es conveniente asegurar el servicio y optimizarlo, dos opciones que tenemos es utilizar comunicaciones bajo SSL y comprimir el recurso web.

Estas tareas son repetitivas y siempre que desarrollo un servicio web me toca lidiar con estos apartados y cada vez lo hago de una manera distinta así que esta vez me he decidido a documentarlo mediante un artículo para en un futuro poder tenerlo como referencia.

En este articulo voy a hablar sobre como encriptar y comprimir las comunicaciones entre un servicio REST y un cliente Android, aunque también se podrá usar una navegador, como Firefox.

El servicio REST está montado sobre una máquina Linux con PHP y desarrollado con Laravel 5.2, por otra parte en el lado del cliente se usa Android con la librería Volley para comunicaciones asincronas.

Decir que este artículo no va a tratar ni de Laravel ni de Volley, aparecerá código correspondiente a estas librerías/frameworks pero no se explicarán, así mismo la instalación y configuración inicial de apache tampoco serán explicadas.

El punto de partida es un servidor Linux con Apache y un servicio REST funcionando, por parte del cliente el punto de partida es un dispositivo Android capaz de consumir el servicio mediante Volley.

El artículo se va a dividir en 2 partes, por una parte la explicación de como hacer funcionar la compresión y por otra parte como hacer funcionar las conexiones seguras.

Comprimir la respuesta del servidor

Cuando tenemos un servicio que va a ser consumido desde un dispositivo móvil me atrevo a decir que la compresión de la respuesta es obligatoria, teniendo en cuenta que las operadoras móviles tarifican por MB consumido, comprimiendo los datos podemos reducir el tamaño en hasta 4 o 5 del tamaño original.

A diferencia de lo que mucha gente opina en internet (como por ejemplo en StackOverflow: http://stackoverflow.com/questions/21144992/android-volley-gzip-response) para hacer funcionar la compresión GZIP en volley no hace falta hacer absolutamente nada. Lo único que tenemos que configurar es nuestro servidor apache.

Primero tenemos que activar el modulo deflate que es el que nos permite realizar la compresión, para ello en la terminal ejecutamos lo siguiente

sudo a2enmod deflate

Ahora lo que tenemos que hacer es modificar el fichero /etc/apache2/apache2.conf y añadir las siguientes directivas

El commando AddOutputFilterByType DEFLATE comprimirá todo aquellos que coincida con el mime-type que le sigue, en este ejemplo comprimirá los ficheros javascript, json, xml, css...

Dependiendo del nivel de compresión que queramos podemos añadir la siguiente directiva

DeflateCompressionLevel 1-9

El valor 1 implica la mínima compresión posible y 9 la máxima. Si no especificamos comprimirá con el máximo nivel posible.

Ahora reiniciamos el servicio apache:

sudo service apache2 restart

Para hacer las pruebas me he creado un recurso simple en laravel

Donde lo que se imprime es un texto bastante grande generado mediante un Lorem ipsum generator (http://es.lipsum.com/).

Si accedemos al recurso en firefox y presionamos Ctrl + Shift + C y vamos a la pestaña “Network”

veremos lo siguiente (Si no aparece nada, una vez se esté posicionado en la pestaña network volver a cargar el recurso)

GZIP en funcionamiento

Podemos ver como el tamaño es de 89KB pero lo que se ha transimitido es 23.87KB, unas 4 veces menos, una ahorro a tener muy en cuenta. Si pulsamos sobre esta petición podremos ver lo siguiente:

Cabeceras de la Resquest y Response

Podemos ver como en las cabeceras de la petición (Request headers) podemos ver la cabecera:

Accept-Encoding: “gzip, deflate”

y en las cabeceras de la respuesta (Response headers) podemos ver la cabecera:

Content-Encoding: “gzip”

Esas 2 cabecerás es lo único necesario para que funcione la compresión GZIP. ¿Pero esto funciona en Volley? Vamos a comprobarlo, para ello vamos a usar wireshark y esnifar las comunicaciones.

En mi caso tengo mi router (192.168.1.101), mi servidor linux (192.168.1.109) y mi Android, del cual no se su ip ni me interesa. Tras una petición de Android el flujo de comunicación será el siguiente:

1 – Android manda la petición a mi router

2 – Mi router envia la petición al servidor

3 – El procesa la petición y genera la respuesta, y la manda al router

4 – Finalmente el router reenvia la petición a mi Android.

Abrimos ahora wireshark y empezamos a capturar tráfico, ahora nos dirijimos a la aplicación Android y hacemos la petición al servidor, cuando hayamos mandado la petición y hayamos recibido la respuesta pausamos wireshark.

Seguramente aunque lo hayamos estado capturando tráfico solamente durante unos segundos tendremos miles de entradas en wireshark. Para aclararnos un poco tenemos que usar la busqueda mediante filtros, para encontrar la petición basta con usar el siguiente comando:

http.request.uri matches "example"

En example debemos poner alguna parte que sepamos de la url de nuestro recurso y así podremos localizar nuestra petición y ver lo siguiente

Request en Wireshark

Esta vez he eliminado la URL de la petición ya que uso un servicio privado. Pero podemos ver como volley ha añadido la cabecera

Accept-Encoding: gzip

Ahora para localizar la respuesta del servidor podemos usar el siguiente filtro

ip.src == 192.168.1.109 && ip.dst == 192.168.1.101 && http

Response en wireshark

Podemos ver como el servidor contesta con la cabecera

Content-Encoding: gzip

Además Wireshark nos dice en la penultima linea que el contenido está codificado con GZIP

Por tanto, resumiendo, volley añade automáticamente la cabecera necesaria para comprimir los datos (esto lo hace mediante el uso de la clase HttpUrlConnection) por contra para que el servidor acepte compresión por GZIP hay que seguir los pasos explicados anteriormnete

IMPORTANTE: Bajo ningún concepto añadir manualmente la cabecera Accept-Encoding: gzip en el método getHeaders de la Request de Volley ya que si se añade la cabecerá manualmente habrá que hacer la descompresión de los datos en GZIP manualmente mediante GZIPInputStream. Tamibén es impostante saber que la clase HttpUrlConnection unicamente está disponible a partir de la API 9 de Android en versiones anteriores usa HttpClient y por tanto la descompresión habrá que hacerla manualmente.

Establecer comunicaciones seguras

En esta parte hay una mayor carga teórica, la cual no voy a explicar, entiendo que si alguien encuentra esto es porque tiene nociones de certificados, autoridades de certificación, cadenas de confianza y claves privadas.

Para empezar debemos generar nuestro certificado y nuestra clave privada, para ello podemos utilizar openssl en linux,

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.crt -days 1000

con openssl hacemos una petición de certificado x509 generando con ello una nueva clave privada RSA de 2048 bits llamada key.pem, el certificado generado será cert.crt y tendrá una validez de 1000 días.

Generación de certificado

A continuación debemos guardar estos dos ficheros generados en un lugar seguro, por ejemplo /etc/apache2/ssl

Ahora tenemos que configurar un host virtual con ssl, por lo general apache viene con uno por defecto, para activarlo debemos ejecutar el siguiente comando:

sudo a2ensite default-ssl.conf

Las 2 primeras líneas de este fichero son

<IfModule mod_ssl.c>

<VirtualHost _default_:443>

Si queremos podemos cambiar el puerto que por defecto es el 443. Tenemos que asegurarnos de que está presente la siguiente directiva

SSLEngine on

y especificar nuestro certificado y clave privada

SSLCertificateFile /etc/apache2/ssl/cert.crt
SSLCertificateKeyFile /etc/apache2/ssl/key.pem

Por último reiniciamos apache mediante

sudo service apache2 restart

Si ahora accedemos al recurso mediante un navegador como firefox (y mediante el protocolo HTTPS y no HTTP) se mostrará lo siguiente

SSL en navegador

Si vamos a Advanced y le damos a Add Exception… y luego a Confirm Security Exception ya podremos acceder al recurso. Ahora falta modificar la aplicación Android para que sea capaz de comunicar mediante ssl con el servicio web.

Ahora si abrimos las herramientas de desarrollador de firefox con Ctrl + Shift + C

ssl3

Vemos como ha aparecido un candado a la izquierda del dominio y además aparece información de seguridad.

Lo primero que debemos hacer es generar un keystore para almacenar nuestro certificado y poder usarlo en Android, para ello nos bajamos de aquí el fichero bcprov-ext-jdk15on-1.46.jar y ejecutamos la siguiente línea en la terminal de Linux

sudo keytool -importcert -v -trustcacerts -file cert.crt -alias IntermediateCA -keystore "./keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-ext-jdk15on-1.46.jar -storetype BKS -storepass "PASSWORD"

Debemos ejecutarlo desde el directorio donde tengamos el fichero bcprov-ext-jdk15on-1.46.jar y el certificado.

Con esto se nos habrá creado un fichero con extensión bks que debemos importar en la carpeta RAW de Android.

En Android lo que debemos hacer ahora es cambiar las rutas y cambiar http por https. Por ejemplo yo siempre tengo las rutas en constantes de la siguiente forma

El tema de las interrogaciones es por el hecho de que siempre que uso URL's me genero un sistema de bindings de parámetros.

A continuación debemos crear un nuevo stack para Volley, en mi caso a dicha clase le he llamado HurlSslStack que extiende de HurlStack. En esta clase lo que debemos hacer es crear el contexto SSL, para ello el constructor de clase recibe un stream del keystore que hemos creado más arriba. En esta clase debemos implementar el método createConnection que será el encargado de crear la conexión, crear el contexto SSL y verificar el host, para verificar el host debemos verificar que el campo "Issue to" o "Emitido a" cuando hemos creado el certificado coincide.