miércoles, 20 de agosto de 2025

Lenguaje LOGO, el "Scratch" de los 80s y 90s

Hoy día para enseñar programación por primera vez a niños (y no tan niños) es habitual usar Scratch, haciendo de la programación algo más visual 
Pero... ¿Que alternativas había antiguamente en los 80s y 90s antes de Scratch? Pues había un lenguaje muy popular, creado en 1967 llamado LOGO, en cual aun siendo de texto, tenía comandos muy simples y la salida era bastante visual al igual que Scratch. En este caso se trataba de hacer dibujos moviendo un puntero representado por una tortuga, de ahí que también se le conociera como "El lenguaje de la tortuga".
Pues queriendo recordar este lenguaje, no solo hice una adaptación al lenguaje C de la tortuga hace unos años, sino que también recientemente encontré una versión online de LOGO bastante buena y que os recomiendo: Turtle Academy.
Pues bien, aunque el lenguaje LOGO es bastante limitado al ser ser de finalidad didáctica, con el único objetivo de hacer dibujos sencillos, usando esta web decidí poner la tortuga al límite, y hacer los programas más bizarros, aquí os los muestro, tenéis los links a los programas haciendo clic en los títulos:

3D game engine voxel space

Os resultará bastante familiar. Sí, se trata de la misma demo que hice anteriormente para la GameBoy Advance, aunque en esta ocasión bastante limitada por la velocidad del interprete LOGO. Aun así el simple hecho de generar pseudo-3D con la tortuga de LOGO es una verdadera locura

Bad Apple!!

Si generar pseudo-3D en LOGO no fue ya suficiente, en esa ocasión genero el FMV completo de "Bad Apple!!" en tiempo real. Los frames están almacenados como un array de números con un número para cada scanline en el que cada número representa los bits de cada pixel (blanco/negro). En esta ocasión y para contrarrestar la lentitud de la tortuga de LOGO para pintar los frames, pongo la tortuga en modo "window" (cuando alcanza un limite, por ejemplo abajo sale por el opuesto, en este caso arriba) le seteo un angulo muy pequeño y lo hago avanzar únicamente en linea recta durante toda la ejecución del programa. De esta forma, la tortuga dibuja las scanlines automáticamente con entrelazado, y lo único que tengo que hacer es cambiar el color conforme avanza recto. ¡Ingenioso y efectivo!

QR text input generator

Aunque los QRs parezcan sencillos, la generación de los datos y la corrección de errores llevan algoritmos complejos. Realmente fue bastante difícil crear este programa con todas las limitaciones de LOGO, pero finalmente lo hice.

3D Raytracing Sphere

¿Raytracing de primitivas 3D en LOGO? jajaj ¿es un chiste? ...Ah ...pues no, no lo es. No hay ningún truco, es raytracing de verdad. Va bastante lento como podeis imaginar, pero claro, hay que recordar lo absurdo que es ejecutar algo así en LOGO.


Interactive maze game

Decompilando el motor LOGO de Turtle Academy descubrí que habían funciones indocumentadas (y rotas, todo hay que decirlo) que permitían obtener la posición del ratón, y los botones del ratón. Que mejor manera de aprovecharlo que haciendo un juego de laberinto interactivo usando un algoritmo de detección de colisiones 2D. Muy probablemente el primer juego interactivo hecho en toda la historia de LOGO.


¿Vulnerar el sandbox de ejecución de LOGO y ejecutar código JavaScript a través de instrucciones LOGO en Turtle Academy? ¡No, eso ya no hay quien se lo crea! Espera... ¿Eso es un canvas? ¿De donde viene esa música? Podría robar cookies, hacer peticiones XHR para darme autolikes a mis programas,... Pero como mi epoca jaker ya terminó, en lugar de eso os dejo con esta demo re-shula
Y por aquí lo dejamos... Tenéis más programas en mi perfil de Turtle Academy.

martes, 10 de septiembre de 2024

Creamos el mejor "Crack No CD" para un juego retro (Tarzán)

 Descarga Tarzan PC Portable aquí.

Aunque el tema del crackeo es un tema delicado, si que es verdad que hay veces donde puede estar medio justificado en abandonware y PCs que ya no disponen de lector de CD. El problema es que estos cracks no siempre son del todo fiables (algunos incluso pueden llevar algún regalito), y los creadores de estos cracks nunca revelan detalles de como lo hicieron, permaneciendo ademas en el anonimato mediante un pseudonimo.

Pues por primera vez, y con motivos didácticos, vamos a crear nuestro propio crack de código abierto para un juego abandonware: Tarzán de Disney Interactive.

Pues bien, este juego aunque copia todos los archivos del juego al disco duro al instalarlo, requiere tener el CD insertado para poder jugar. Si abres el juego sin el CD aparece la siguiente pantalla y no permite jugar

Pues tras un breve análisis, detectamos que existe un flag en memoria en 0x837A24 que indica cuando el juego original esta insertado, y buscando la rutina que setea este flag encontramos lo siguiente
En el primer call el juego comprueba que hay un CD insertado y que contiene determinados archivos, haciendo luego comprobaciones adicionales en el segundo call. Pues bien, nosotros queremos setear siempre ese flag sin hacer todas estas comprobaciones, así que reemplazaremos todas las instrucciones hasta el mov del final por nop.
"TARZAN.EXE"+A39C9: //CD Check db 90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90
Y tampoco nos olvidemos de dejar nuestra firma ;) reemplazaremos el mensaje de CPU con MMX ya que en 2024 no es que nos aporte mucha información
"TARZAN.EXE"+1050E0: //Crack NOCD signature db 'CRACK NOCD JUANMV94',0 "TARZAN.EXE"+8FF33: db 90,90,90,90,90,90,90,90,90
Y... voilà. ¡Crackeo completo! Ya podemos jugar sin CD

FIN


Pero... Esperad un minuto... ¡El juego no tiene música! Resulta que el juego es un CD mixto y la música se encuentra en los distintos tracks del CD.
Y aquí es donde sacamos el armamento pesado, y procedemos a hacer una locura que a ningún cracker se le ocurriría hacer...
Vamos a reescribir las rutinas del juego que leen las pistas del CD, para que lean ficheros MP3 en su lugar ¡y todo ello en puro ensamblador!
Esto lo hacemos usando la librería WinMM que ya usaba el juego, concrétamente usando comandos MCI.
Pues bien, tenemos que localizar las funciones del juego de "reproducir el track XX", "parar CD",... y reescribirlas, aparte de almacenar un handle al archivo MP3 que se este reproduciendo en algún sitio. Nos quedamos con lo siguiente:
define(MUSHANDLE,1051C8) "TARZAN.EXE"+89020: //Stop track push 00 push 00 push 0804 //MCI_CLOSE push ["TARZAN.EXE"+MUSHANDLE] call dword ptr ["TARZAN.EXE"+AF234] //WINMM.mciSendCommandA mov ["TARZAN.EXE"+MUSHANDLE],00000000 ret "TARZAN.EXE"+88FB0: //Disable music call "TARZAN.EXE"+89020 //Stop track ret "TARZAN.EXE"+89070: //Request track mov eax,[esp+04] push 00 push eax call "TARZAN.EXE"+89170 //Play track add esp,08 ret "TARZAN.EXE"+89170: //Play track mov eax,["TARZAN.EXE"+12A5C4] test eax,eax //Music enabled? je RETPLAY sub esp,0C //Alloc 12 bytes for file name push [esp+10] //Track no push FILENAME //File name template with %02d lea eax,[esp+08] push eax call "TARZAN.EXE"+A4190 //sprintf call "TARZAN.EXE"+89020 //Stop track //push MCI_OPEN_PARMS to stack push 00 //LPCTSTR lpstrAlias; lea eax,[esp+10] push eax push MPEGVIDEO //LPCTSTR lpstrDeviceType; push 00 //MCIDEVICEID wDeviceID; push 00 //DWORD_PTR dwCallback; push esp //MCI_OPEN_PARMS push 2200 //MCI_OPEN_ELEMENT | MCI_OPEN_TYPE push 0803 //MCI_OPEN push 00 call dword ptr ["TARZAN.EXE"+AF234] //WINMM.mciSendCommandA mov eax,[esp+4] //store handle mov ["TARZAN.EXE"+MUSHANDLE],eax push MCI_PLAY_PARMS push 00010000 //MCI_DGV_PLAY_REPEAT push 0806 //MCI_PLAY push [esp+10] call dword ptr ["TARZAN.EXE"+AF234] //WINMM.mciSendCommandA add esp,2C RETPLAY: ret MCI_PLAY_PARMS: dd 0 //DWORD_PTR dwCallback; dd 0 //DWORD dwFrom; dd 0 //DWORD dwTo; MPEGVIDEO: db 'mpegvideo',0 FILENAME: db 'MUS/%02d.MP3',0
* Os habréis fijado que hay una función que solicita reproducir un track, y otra que procede a reproducirlo. Esta primera función realizaba varios checks del CD que no nos interesan, así que la re-implementamos de forma que únicamente re-ordenará los parámetros y llamará a la segunda función sin realizar ningún check.
* La función que silencia el audio del CD al des-habilitar la música en el menú de opciones la simplificaremos a simplemente parar la reproducción. No es el mismo comportamiento exacto, pero nos vale.
* La función que reproduce el track comprobará que la música este habilitada en el menú de opciones, y convertirá ese numero de track en un path a un archivo MP3 con sprintf, de forma que el track 2 sea por ejemplo "MUS/02.MP3", lo cargará y lo empezará a reproducir de inmediato en modo repetición, habiendo parado previamente la reproducción previa en caso de existir.

¡Y ahora sí! Extraemos los tracks del CD a MP3 y ya podemos jugar a nuestro juego con la música del CD original en un PC sin unidad de disco.

Hacedme saber si queréis más contenido como este en los comentarios

jueves, 8 de febrero de 2024

¿Se pueden predecir los números aleatorios de un videojuego?

Aunque la mayoria de veces esto es muy complicado, o prácticamente imposible, existen ciertas implementaciones de los PRNG en las que puede resultar bastante sencillo predecir estos números.
En esta ocasión me centro en un par de juegos J2ME elegidos al azar, uno de parchís y otro de ruleta, y me dispongo a predecir los números que generará el juego

domingo, 19 de noviembre de 2023

Generador de códigos de amigo para Torre Miau (Meow Tower)

 
 
Recientemente me descargué un juego de nonogramas para el móvil llamado Meow Tower
En este juego en concreto concreto vas subiendo de nivel, desbloqueando "gatos", aspectos, y temas. Pero existen varios de esos desbloqueables que la única manera de conseguirlos es mediante códigos de amigo. 5 en total.

Pero... ¿Y si no tienes amigos? :( Nah, fuera coñas, tú no vas a molestar a nadie pidiendo que se instale el jueguecito para que te de su p*** código. Ademas para evitar que la gente comparta los códigos de amigo en grupos de Facebook o Reddit estos códigos una vez se generan caducan a los 15 minutos.
Pues bien, hay un dicho popular que se remonta a hace miles de años que dice que quien es hacker, ya lo es para toda la vida, así que ahí tenéis hermosos, un generador de códigos de amigo para que no tengáis que molestar a nadie más :')

viernes, 1 de septiembre de 2023

Frikada del mes: Crackeando un juego J2ME de mi infancia

Hace muchismos años, estamos hablando de cuando los teléfonos móviles aun no tenían pantalla táctil, las marcas de moda eran Nokia y Sony Ericsson, y los juegos que se descargaban en formato .JAR no te pedían microtransacciones, hubo uno en especial que me llamó bastante la atención. Se trataba de un juego de golf que era capaz de generar 3D incluso en los teléfonos más sencillos llamado Par 3 Golf.

No os imagináis la de veces que completé el primer nivel, y digo esto porque el juego te pedía que comprases una clave si querías jugar al resto de niveles. Esta clave es vinculada a un PIN que cambiaba si re-instalabas el juego y no era precisamente baratica la p** clave.
Pues bien, eso fue mucho antes de que me convirtiese en un friki, así que ahora llegó el momento de crackear finalmente el juego después de tantos años. Para ello tan solo necesitamos un decompilador de Java. Empecemos por ver de donde viene el valor del PIN:
Antes de que os asustéis debo deciros que el código decompilado aparte de no incluir nombres de variables/funciones, las pocas que sí tienen están ofuscadas usando términos del lenguaje Java aleatorias como append, insert, equals, parseInt... que sus nombres no tienen ninguna relación con lo que hacen realmente. Esto esta hecho con la única intención de confundir a los hackers de ingeniería inversa como yo. Buena jugada, ResetGame. 
Os hago un resumen, la función D checkea mediante la función AI.I si hay datos guardados del juego (lo cual incluye el PIN) y si no existen porque es la primera vez que se abre el juego, setea el PIN (que está en la dirección de almacenamiento 6) a los últimos 16 bits bits del timestamp en ese momento. Lo cual viene siendo... aleatoriedad total.
Pero... un momento... 16 bits significa que tenemos numeros del 0-65535 pero el PIN tiene 6 digitos. WTF??
Miremos el codigo que imprime el PIN:
El PIN se obtiene con la funcion de "Obtener valor de memoria" this.C para la dirección 6. Pues al resultado que se obtuvo de (timestamp & 0xFFFF) se le va a hacer padding con 0s hasta tener 5 cifras, por ejemplo, si el valor es 999 quedará 00999. Y finalmente el primer dígito será la suma de estos 5 digitos modulo 10. En este caso 0+0+9+9+9=27 por lo que nos quedamos con el 7 y el PIN mostrado sería 700999.
Lo mismo aplica con mi PIN del primer screenshot: 1+7+4+6+6=24, por lo que el primer digito del PIN será... sorpresa.
Pero vayamos a lo importante... ¿Como podemos generar una clave a partir del PIN? Vayamos a la funcion que procesa el valor introducido...
Lo primero que hace es borrar el primer dígito que introducimos... Interesante, el primer dígito de la clave no se tiene en cuenta. Después guarda en la posición 8 del almacenamiento el valor del PIN introducido, sea correcto o no.
Pues bien, resulta que hay una función que se llama en varias partes del juego que comprueba si la última clave introducida coincide con el PIN denominada "length" que a su vez aplica una función matemática que han llamado "parseInt" al PIN y este resultado debe coincidir con la clave introducida.
¡Ya esta! Si no os han sangrados los ojos viendo los nombres ofuscados de las funciones, os daréis cuenta de que la clave a introducir debe ser el resultado de (PIN<<5 & 0xFFFF) | (PIN >> 11 & 0x1F) con un digito cualquiera 0-9 delante de ese resultado. Os dejo Un calculador de claves que podeis usar desde el navegador:
Introduzca PIN:
Más tarde apareció... Par 72 Golf, que si me preguntáis la diferencia con el 3 la verdad no lo se ya que el juego es prácticamente idéntico aunque con más niveles. En este caso se puede decir que directamente no existía PIN, ya que siempre mostraba el mismo (RESETgame). Veamos lo que hace en esta ocasión:


Pues vemos que en esta ocasión el valor que se almacena del timestamp no son los 16 bits menos significativos, sino que es el número de día (1000*60*60*24). Ademas es muy curioso, ya que parece que la clave a introducir sería ese número de día de la instalación con un margen de 15 días a partir de los cuales la clave que te entregan dejaría de ser valida. Aparte de eso, también existe una clave "55205" que siempre funcionaría e imagino que únicamente se entregaría en caso de "emergencia" cuando alguien se quejase de que la clave basada en días que le entregaron no funcionaba. Pero... tenemos un problema. Por alguna razón le dieron fecha de caducidad a las keys basadas en el día actual. Con la operación & 0x3FFF impiden que se puedan introducir fechas posteriores a Noviembre de 2014, así que a día de hoy la unica forma de desbloquear el juego es con la clave "55205".

En fin, si de verdad has llegado hasta aquí, que sepas que eres 1 entre un millón. ¡Enhorabuena!

sábado, 29 de abril de 2023

Instagram: ¿Quien te deja de seguir? ¿Quien no te sigue de vuelta? Vuelve Insta-Script

Una de las tareas que más le interesa a los profesionales de Instagram es la de poder extraer la lista de sus seguidores a un fichero de texto. Esto permite poder comparar su lista de seguidores con valores anteriores (y detectar unfollowers) así como compararlo con la lista de gente a la que siguen, y detectar cuentas que no te siguen de vuelta.

En 2015 cree por primera vez Insta-script como un script para Linux que obtenía estas listas y mostraba las diferencias, pero eventualmente dejó de funcionar cuando la API de Instagram empezó a requerir estar logueado para obtener estas listas.

8 años después (fijaos si me he esperado) he re-implementado Insta-Script como un script JS que se ejecuta en el dev-tools del navegador (esa cosa que aparece cuando pulsas F12 en el navegador) de forma que es tan sencillo como abrir instagram.com en el navegador web del PC, loguearte, ejecutar el siguiente código en la consola del dev-tools, y se descargará automaticamente la lista de seguidores en formato txt:


En el primer parámetro userid debemos escribir el ID numérico de la cuenta de Instagram para obtener los seguidores, o en caso de no saberlo, el nombre de usuario de Instagram.
En el segundo parametro mode usaremos el valor "followers" o "following" dependiendo de si queremos extraer la lista de seguidores o personas a las que se siguen. La lista que obtendremos tendrá el siguiente aspecto:


Como podéis comprobar, obtiene los IDs de Instagram ordenados de menor a mayor seguidos del nombre de usuario. Esto permite detectar cuando un usuario simplemente se ha cambiado el nombre de usuario, y no confundirlo con un follow-unfollow de 2 usuarios distintos, así como evitar que se desordenen las cuentas cuando vayamos a comparar archivos.
Por último comentar que si la cuenta de la que estamos extrayendo seguidores no es la cuenta con la que estamos logueados, es posible que se filtren algunas de las cuentas de la lista, por lo que recomiendo siempre loguearse en la cuenta de la que queremos extraer la lista.

Y para terminar... ¿Como obtener los follows que no te siguen de vuelta? Pues en esta ocasión lo hice mediante un batch para Windows. Más sencillo imposible. Creais un archivo unfollowbacks.bat en un directorio con ambos txt con el siguiente contenido y lo ejecutais: