Humanos en problemas (II)

En la primera parte vimos algunas cosas básicas del debugger de DOSBox, y llegamos hasta el comienzo del programa principal ya desencriptado. Para retomar nuestro análisis, no hace falta volver sobre los mismos pasos. (Excepto abrir el DOSBox con debugger y activarlo escribiendo debug humans, claro). Habíamos hablado de que la sección Code Overview funciona como una ventana que podemos desplazar con las flechas del cursor. Pero también podemos apuntarla a una dirección determinada escribiendo C [segmento]:[desplazamiento]. Escribamos C CS:0132, que es donde sabemos termina la rutina de arranque, y coloquemos un freno con F9.

Aquí hace falta hacer un par de aclaraciones. En primer lugar, que CS no es otra cosa que un registro que indica el segmento de código actual. (Momento para mirar en Register Overview y ver que no miento, al menos sobre esta cuestión.) Venimos usándolo en lugar de un valor fijo porque éste puede cambiar, no sólo durante la ejecución, sino también de una máquina a otra, dependiendo de la configuración, controladores y programas residentes. En segundo lugar, sepamos que sólo apuntamos la ventana, pero el registro IP (instruction pointer) sigue indicando la dirección original (0000) y es desde ahí que el procesador va a continuar. Pulsemos F5 para ejecutar toda la rutina de arranque (desde CS:0000 hasta llegar a CS:0132), demos un paso más con F10, y estaremos nuevamente ante el comienzo del programa principal:

0000: call 0000816E
0003: call 000056BC
0006: call 00000677
0009: call 0000B43C         ;esta es la que nos interesa
000C: mov  [00EF4],0000

A diferencia de la vez anterior, ahora vamos a ejecutar sólo las tres primeras subrutinas (¿hace falta que aclare que tenemos que pulsar F10 tres veces? – bárbaro, gracias). Sabemos que en la cuarta está el código a desmenuzar así que, en vez de F10, pulsemos F11 (step into). ¿Cuál es la diferencia? Como su nombre lo sugiere, en vez de ejecutar la llamada call 0000B43C completa, dimos un paso “hacia adentro” de la subrutina. Una vez dentro, seguiremos con el habitual F10 (step over). Tomemos nota de que estamos en CS:B43C, que es nuestro nuevo punto de partida.

Empecemos a caminar esta nueva etapa y veremos aparecer la pantalla de carga (esa que dice «The Humans – Spanish Version»). Luego, en CS:B4C2 y CS:B4D1, aparecen dos saltos condicionales hacia atrás. Ya sabemos cómo lidiar con ellos (sí, se pueden saltear los dos juntos). Al llegar a CS:B505 pongamos un freno, pero antes borremos todos los anteriores (BPDEL *) para poder retomar directamente desde aquí cuantas veces haga falta:

B505: mov di,4894
B508: mov bp,0028       ;mostrar pantalla
B50B: mov bx,0000       ;solicitando la
B50E: mov cx,0100       ;página correspondiente
B511: call 00008C08     ;al dibujo
B514: call 00008BE7
B517: jmps 0000B574     ;ingreso y verificación (¿no vuelve?)
B519: mov di,4594
B51C: mov bp,0023       ;borrar pantalla
B51F: mov bx,0000       ;tras el ingreso correcto
B522: mov cx,0100       ;(nótese la simetría
B525: call 00008C08     ;con el bloque anterior)
B528: call 00008BE7

Acá está la papa. En estas líneas se muestra la pantalla con la señorita, se piden las claves y se vuelve a borrar la pantalla. Sin embargo, hay algo que no cierra. El salto en CS:B517 debería, en principio, ser una llamada, ya que cuando damos una respuesta correcta el flujo del programa continúa en CS:B519 (para comprobarlo sólo hace falta poner un freno ahí). Si nuestra respuesta no es satisfactoria, en cambio, iremos a parar a la consola del DOS con el mensaje “Program protection failure, Please re-run”, sin haber pasado por CS:B519.

Lo que esto significa es que a partir de CS:B574 está la lectura del teclado y el control de autenticidad. Si algo falla, el programa no vuelve a su curso normal. Esto nos lleva a realizar un experimento casi cantado. Si el fragmento citado contiene todo el proceso, por qué no saltearlo y ver qué pasa. Salgamos al DOS pulsando Alt-X, volvamos a activar el debugger escribiendo debug humans, y pulsemos F5 para dejar correr el programa. Cuando la ejecución se detenga en CS:B505 escribamos SR IP B52B. Esta orden cambia el valor del registro IP que mencionábamos antes. Es decir que cuando dejemos correr nuevamente el programa, en vez de continuar en CS:B505 lo hará desde CS:B52B, justo después del bloque.

Pulsemos F5. Suena la melodía y vemos el logo de Mirage. ¡¿Lo logramos?! No cantemos victoria: ni bien tratemos de continuar nos encontraremos de regreso en la consola del DOS. ¡A no desalentarnos! No habremos logrado quebrar la protección, pero es evidente que estamos bien encaminados. Y además descubrimos que más adelante existen otros puntos en los que se controla el dato ingresado. En lugar de buscarlos uno por uno (sin saber cuántos son en total), nos conviene identificar y reproducir el efecto de ingresar el número de página correcto. Vamos a tener que zambullirnos en el código localizado en CS:B574, que es ahora nuestro nuevo punto de referencia.

Un maestro, una causa, un efecto

Volvamos a empezar, y al llegar a CS:B505 pongamos un freno en CS:B574, para ver qué pasa al ingresar el número de página. Las rutinas de lectura del teclado suelen consistir en un gran bucle que compara los códigos suministrados por una función del DOS o de la BIOS para determinar qué tecla ha sido pulsada, llevar la cuenta de los caracteres ingresados, y salir cuando el ingreso esté completo. Recorriendo el código veremos que en CS:B5AB hay un salto al comienzo, que cierra el bucle del que hablábamos. Pero también vemos la salida:

B5A2: mov  al,[457B]
B5A5: or   al,al
B5A7: jne  0000B5AD
B5A9: loop 0000B59F
B5AB: jmps 0000B574
B5AD: mov  b,[457B],00
B5B2: cmp  al,0D
B5B4: je   0000B5F2
B5B6: cmp  al,0E
B5B8: je   0000B5DC
B5BA: cmp  al,30
B5BC: jb   0000B574
B5BE: cmp  al,39
B5C0: ja   0000B574

A partir de CS:B5B2 comienza una serie de comparaciones sobre el caracter ingresado, que entre otras cosas descarta cualquier letra o símbolo que no sea un número del 0 al 9 (ver CS:B5BA y CS:B5BE, valores en ASCII). Pero la primera comparación de todas es contra el número hexadecimal 0Dh (¡bendito número 13 de la suerte!) que corresponde a la tecla Intro. Podemos estar seguros que esa es la salida que buscamos, así que pongamos un freno en CS:B5F2, dejemos correr el programa e ingresemos el número de página correcto.

Tal como lo previmos, el debugger retomó el control en CS:B5F2. Avancemos por el código para ver adónde nos lleva, y tras unos pocos pasos nos encontraremos saltando entre CS:B63A y CS:B637. Hemos venido a parar a un callejón sin salida, cuyo propósito es precisamente que le perdamos el rastro a la ejecución. La buena noticia es que no hace falta seguirlo.

B633: mov    [3ECD],bp
B637: mov    bx,B637
B63A: jmp    bx

Justo antes de estancarse, el código almacena el contenido del registro BP, resultado de unos cálculos hechos líneas antes, en la dirección DS:3ECD. Apuntemos la ventana Data Overview unas posiciones antes, para tener un contexto, escribiendo D DS:3EC0 y ver si podemos sacar alguna conclusión. El valor de 16 bits (word) almacenado en DS:3ECD (señalado con B en la captura) es idéntico al de la posición DS:3ECB (señalado con A). Y si repetimos el experimento, respondiendo correctamente a un dibujo diferente, veremos que el valor A cambia, y el correspondiente valor calculado (B) coincide con él. Es hora de repetir el mismo experimento de antes, pero con una variante: una vez detenidos en CS:B505 copiaremos el contenido de la memoria de A a B, antes de modificar el IP para saltear toda la rutina, siguiendo estos pasos:

  1. D DS:3ECB (apuntar la ventana de datos)
  2. SM DS:3ECD <byte> <byte> (copiar los dos primeros bytes de Data Overview)
  3. SR IP B52B (modificar el IP para saltear la rutina de claves)

Dejemos correr el programa y esta vez pasamos sin problemas a la segunda presentación, al menú y podemos disfrutar del juego, nivel tras nivel. Esta vez sí hemos quebrado la protección.

¿Y ahora qué pasa, eh?

El método funciona pero está claro que todavía tenemos pendiente elaborar un parche que lo implemente. Dicho parche tendrá que hacer su trabajo una vez que el juego esté desencriptado en memoria. Y algún lector sagaz se habrá percatado de una complicación adicional: el valor correspondiente al dibujo (aquel que señalamos con A) se calcula aleatoriamente cada vez que el juego se pone en funcionamiento. Una posible solución es localizar la rutina que calcula un nuevo valor y anularla.

Dado que esta segunda parte también se ha extendido bastante, prefiero dejar la implementación del parche para la próxima (y última) entrega. Mientras tanto, recomiendo a quien haya leído esta guía practicar localizando la rutina que hay que anular para que el valor original no cambie. También puede experimentar con la edición de GameTek de este juego, donde la protección fue modificada levemente, agregándole una complicación adicional.

PS: Existe también una versión en CD-ROM que contiene el juego original combinado con los niveles del disco de expansión. Si bien en este caso la protección es distinta, al tratarse de un cd-check, la rutina de arranque es idéntica y podemos llegar al inicio del programa con los metodos aquí explicados.

Humanos en problemas (I)

Días atrás, en pleno encierro forzoso “aislamiento social preventivo y obligatorio”, colaboré en abandonsocios con un crack para la versión en castellano de The Humans. De ahí surgió la idea de hacer una guía paso a paso explicando el procedimiento, cosa que resultó bastante más difícil que el propio crack. Como la protección no es demasiado compleja, decidí orientar la guía a quienes ya tengan algún conocimiento de lenguaje ensamblador y quieran incursionar en el apasionante mundo de la desprotección de juegos antiguos. En esta primera entrega vamos a familiarizarnos con las funciones principales de un debugger, a medida que avancemos sobre el código de arranque del juego. ¿Qué es un debugger? Una herramienta interactiva que nos permite analizar un programa mientras éste se ejecuta.

Los pasos de la guía están descriptos para el debugger de DOSBox, porque fue la herramienta que utilicé al desproteger el juego y porque cualquier aficionado actual a los juegos de DOS seguramente está familiarizado con dicho emulador, ya sea que utilice Windows o Linux. Cabe aclarar que la instalación estándar no incluye el debugger; es necesario descargar un ejecutable alternativo y agregárselo. Si utilizamos Windows, debemos descargar el ejecutable correspondiente y moverlo a la carpeta donde tengamos instalado DOSBox. En caso de usar Linux, en esta página están disponibles los paquetes correspondientes, e instrucciones de instalación desde consola. Ambos enlaces corresponden a la versión vigente a la fecha (0.74-3).

Un pantallazo al debugger

Si iniciamos DOSBox con el nuevo ejecutable (dosbox-debug), en lugar de la habitual ventana de estado se abrirá otra llamada “DOSBox Debugger”. Pulsemos alt-pausa para activarla y observemos que está compuesta por cinco secciones, cada una encabezada por una barra color celeste con su título:

  • Register Overview: contenido de los registros del procesador
  • Data Overview: contenido de la memoria, en hexadecimal y ASCII
  • Code Overview: contenido de la memoria interpretado como código ejecutable
  • Variable Overview: contenido de variables definidas por el usuario
  • OutPut/Input: mensajes informativos

Las secciones Data, Code e Input/Output funcionan como ventanas que pueden desplazarse pulsando las teclas indicadas en el título («Scroll»).

Mientras tanto, el programa en ejecución ha quedado en suspenso, cosa que podemos comprobar viendo que el apuntador del DOS ya no parpadea. Para retomar la actividad y devolver el foco a la ventana principal, debemos indicarle al debugger, pulsando la tecla F5 (run), que deje correr libremente el código. Otra forma, quizás más útil, de tomar el control desde el debugger es hacerlo desde el comienzo del programa a analizar. Escribamos debug humans desde el directorio donde tenemos instalado el juego. Esta orden le dice a DOSBox que cargue el juego en memoria y que en vez de ejecutarlo le transfiera el control al debugger.

Quiero ver, quiero entrar

The Humans está protegido con un doc-check, es decir, la verificación de que el usuario tiene en su poder algún elemento adicional difícil de duplicar (instrucciones, rueda de códigos, etc.). Ni bien cargamos el juego, una señorita nos pregunta en qué página del manual aparece un dibujo determinado. Como esto ocurre incluso antes de la presentación, vamos a intentar seguir el flujo del programa hasta llegar a ese punto. Prestemos atención a la sección Code Overview. Estamos en la dirección cero del segmento de código actual (CS:0000) ante la instrucción jmps 0176. Cada vez que pulsamos F10 (step over), el debugger deja que se ejecute la instrucción actual (señalada en color verde) y avanza a la siguiente. Esto se refleja también en el apuntador de instrucción (registro EIP en la sección Code Overview).

Debugger screenshotVayamos avanzando paso a paso, sin profundizar demasiado en los detalles pero intentando seguir el hilo del programa. Nuestro objetivo es llegar rápidamente hasta el fragmento de código en que se encuentra la protección. Al llegar a CS:01CA encontramos un salto condicional hacia atrás. Si continuáramos como hasta ahora, pasaríamos cientos de veces por el mismo fragmento de código. ¡Podemos emplear mejor nuestro tiempo, incluso en cuarentena! Bajemos a la siguiente instrucción utilizando el cursor (CS:01CC, ver captura) y pulsemos F9 (breakpoint) para poner un freno, que el debugger señala en color rojo. Si ahora dejamos correr el programa (F5), como hicimos al principio, DOSBox ejecutará reiteradamente las instrucciones precedentes hasta que la condición deje de cumplirse. Recién ahí pasará a CS:01CC y al toparse con nuestro freno volveremos a tomar el control desde el debugger.

Continuemos paso a paso hasta CS:011D, donde encontraremos otro salto hacia atrás. La manera de saltearlo es la misma, y es una excelente oportunidad para poner en práctica lo que acabamos de aprender. Un poco más adelante, más precisamente en CS:0132, encontramos la última instrucción de este fragmento: jmp far word cs:[0138]. Pulsemos F10 una vez más y preparémonos para la siguiente etapa.

Del corazón pa’ dentro

Observemos que estamos otra vez en la dirección CS:0000, pero de un segmento de código distinto. Aunque no lo parezca, hemos avanzado bastante. Sin demasiado esfuerzo atravesamos la rutina de arranque y tenemos ante nuestros ojos el comienzo del programa principal ya desencriptado:

0000: call 0000816E
0003: call 000056BC
0006: call 00000677
0009: call 0000B43C         ;¿lobo, estás?
000C: mov  [00EF4],0000

De entrada nomás llama a cuatro subrutinas. Vayamos ejecutándolas una por una, pulsando F10. Las tres primeras terminan sin novedades, pero al pasar a la cuarta vemos la pantalla de carga y llega la señorita a pedirnos el número de página. Contestemos el dato correcto y veremos el logo de Mirage y el comienzo de la presentación antes de que el debugger recupere el control en CS:000C.

Con esto ya podemos dirigir nuestro análisis a la subrutina que comienza en CS:B43C. Y así debemos seguir como si se tratase de una muñequita rusa, pelando capa tras capa hasta llegar al meollo de la cuestión. Pero como esto se ha hecho ya bastante largo, vamos a dejarlo aquí hasta la próxima entrega.

Construyendo un adaptador para filtro de agua

Jamás imaginé, mientras compraba un purificador de agua, que me vería obligado a incursionar en el Diseño Asistido por Computadora para poder instalarlo. Después de probar sin éxito con los adaptadores provistos por el fabricante, comencé a recorrer ferreterías y casas de sanitarios en busca de una reducción apropiada. Pero los días pasaban entre promesas difusas y excusas repetidas y la bendita pieza no aparecía.

Llave de paso del filtro de agua, instalada con el adaptador impreso.
Llave de paso del filtro de agua, instalada con el adaptador impreso.

Entonces se me ocurrió preguntarle a mi amigo taos78, que desde hace varios meses está metido en el asunto de las impresoras 3D, si sería factible imprimir la pieza. Confieso que dudaba de la precisión de estos aparatos para producir una rosca funcional, pero quedamos en que yo prepararía un modelo usando FreeCAD y él se encargaría de la impresión.

AdaptadorMkI
Primer intento. Nótese que se trata de dos piezas encimadas.

Después de instalar el software e investigar en los foros para hacerme una idea de por dónde empezar, encontré un hilo donde el usuario ulrich1a ofrecía un perfil de la rosca ISO, junto con unas instrucciones poco intuitivas para construir una superficie roscada. Con un poco de paciencia y tomando las medidas de un modo bastante precario, armé el primer prototipo del adaptador.

A pesar de estar siempre muy ocupado (y eso que ya no se dedica a catar flanes mixtos), al día siguiente taos78 me trajo la pieza, de una calidad sorprendentemente buena. También me advirtió sobre errores en el modelo y el hecho de que la pieza, tal como fue creada, era hueca por dentro. Así y todo la rosca superior calzó perfectamente en la canilla, pero la parte inferior no tenía las dimensiones correctas (mala mía).

Para el segundo prototipo tomé las medidas con más cuidado, y me propuse encontrar un método más intuitivo para crear las roscas. Partiendo del perfil ISO, igual que antes, esta vez creé un helicoidal del mismo díametro que la rosca buscada y se lo resté a un cilindro macizo. Corregí el paso de la rosca superior, de 1mm a 1,5mm, y agregué un suplemento en el centro, para que la rosca inferior quedara a nivel.

Aquí volví a equivocarme, ya que la idea original era que el suplemento central fuera angosto y sirviera para calzar un anillo de goma que -de paso- asegurara la hermeticidad. Pero el angostamiento iba a requerir material de soporte para su correcta impresión, entonces lo remplacé a último momento por un sólido que me quedó demasiado grande. Una pena porque, como puede verse en la foto, el resultado impreso (en negro) quedó muy bien.

Obligado a corregir el modelo de la pieza, decidí rehacerlo desde el comienzo, incorporando detalles que de entrada me parecían «pedir demasiado». Finalmente, el adaptador quedó compuesto por una base roscada de 22mm de diámetro, con un paso de 1mm, y 4mm de altura. Antes de roscar el cilindro, le apliqué un bisel que sirve en su base para centrar la rosca, y en su parte superior para coincidir con el suplemento central, de 20mm de diámetro.

Barolo sostiene pieza final.
Barolo quizo participar del proceso constructivo.

Éste tiene una curva en su parte superior que facilita su asentamiento en el interior de la canilla (también de 1mm, para coincidir con la parte superior del adaptador). La parte superior consiste en otro cilindro roscado, de 18mm de diámetro una rosca de 1,5mm de paso, con bisel en la parte superior. El conjunto se completa con un calado hexagonal que, además del paso del agua, permite ajustarlo a la canilla mediante una llave Allen.

Delirios de pinball

Durante muchos años, probablemente debido a la complejidad técnica, las máquinas de pinball estuvieron a salvo de sus pares electrónicos. Muchas fueron las adaptaciones que intentaron capturar, con escaso éxito, la esencia del juego. Algunos, aceptando la imposición del formato horizontal de los televisores, ensayaron con mesas más anchas que largas; otros respetaron la proporción natural, pagando el costo con una pantalla dividida o reduciendo considerablemente el tamaño de la mesa.

Night Mission
La versión 3.0 de 1988

Incluso hubo ideas ingeniosas como el Pinball Construction Set (una especie de Meccano de los pinball), pero los resultados no llegaban muy lejos: salvo honrosas excepciones como el Night Mission Pinball de SubLOGIC, no recuerdo haberme entusiasmado con ninguno.

No fue hasta 1992, y no es de sorprender que el milagro haya ocurrido en la Amiga, que la entonces desconocida Digital Illusions creó el genial Pinball Dreams. Por primera vez estaban todos los ingredientes necesarios para producir un juego adictivo, comenzando por una mecánica suficientemente realista, siguiendo con una mesa vertical que se desplaza suavemente por la pantalla, y terminando con un acompañamiento musical de primera. A partir de ahí fue «un partidito más» mañana, tarde y noche…

Party LandLa propia Digital Illusions demostró, sólo unos meses después, que no estaba dicha la última palabra destronando a su propio juego con el increíble Pinball Fantasies. Tras sólo unas horas me convertí en un cobayito cuya única satisfacción era efectuar sucesivos tiros a las rampas opuestas para escuchar el «Five million!» y así seguir aumentando la cuenta. Es el día de hoy que la mesa Party Land sigue siendo una de mis favoritas.

No hay dos sin tres

Entonces llegó 1995 y un día como cualquier otro mi entonces amigo y compañero de estudios Bosterix me pasó el dato de que el flamante Pinball Illusions estaba disponible en uno de los BBS que frecuentábamos. Conectado a las 5 de la mañana terminé de descargar el lanzamiento de Hybrid de la versión en CD: un enorme ejecutable de 50MB, una presentación cinematográfica donde Digital Illusions se jactaba con toda razón de su impecable trayectoria, cuatro mesas distintas y al elegir cualquiera de ellas… silencio absoluto.

Así fue la «era dorada» del CD-ROM: los cráneos de las editoriales vieron al nuevo soporte y sus inconmensurables 650MB como una nueva variante de llave anti-piratería, para lo cual a todo había que agregarle animaciones en 3D, voces (¡como en las odiosas versiones parlantes de las aventuras de Lucas Arts!), fragmentos fílmicos de dudosa calidad o simplemente, como en este caso, poner la música como pistas de audio.

Para colmo, 21st Century Entertainment sacó también una versión en sólo tres diskettes que traía toda su música sintetizada, pero no incluía la cuarta mesa (Viking Tales) que, lógicamente, se convirtió en mi favorita. Y no fue solamente por ser la «figurita difícil» sino también porque la canción de apertura, coreada por una manga de vikingos ebrios (bueno, cada uno…) a la manera en que hoy se corea el Himno Nacional Argentino en los estadios, era francamente irresistible.

Pero volviendo a la cuestión que nos ocupa, ocurrió que una vez, en medio de alguno de esos baches auditivos, tuve que poner pausa para atender un llamado y cuando retomé el partido aconteció algo inesperado: el silencio se volvió música. Era evidente que el ejecutable de Pinball Illusions CD incluía toda la música original, sólo que en algunas circunstancias ésta era enmudecida para ceder el micrófono (¡je!) a su versión alternativa en CD-Audio.

Pasó el tiempo, estudios, trabajo y familia, y hace algunos días caí en cuenta que se cumplen nada menos que 20 años de la aparición de este juego, ¿y qué mejor para conmemorarlo que hacer una edición que funcione al 100% sin necesidad del CD?

DPMI o no DPMI. ¿Es ésa la cuestión?

A diferencia de sus antecesores, Pinball Illusions viene empaquetado en un solo archivo de unos 4MB (trabajé sobre la versión incluída en el Pinball Power Pack, para no arrastrar los 40 y pico de megabytes de relleno de la versión original). El juego trabaja en modo protegido y se rehusa a funcionar bajo Windows, lo cual nos cierra la posibilidad de usar SoftICE para inspeccionarlo -o quizás no.

Después de una pequeña rutina en CS:0070 que desencripta el stub, podemos hacer un vuelco de 5210h bytes a partir CS:0100, y observar el código tranquilos. Lo primero que vemos, en texto plano, son algunos mensajes interesantes sobre DPMI y compatibilidad con Windows.

Efectivamente, en CS:16C9 está la cadena «DPMI detected» y es mostrada por una rutina huérfana que empieza en CS:1667. Veamos si podemos rehabilitarla. Las subrutinas de detección de distintas API de gestión de memoria colocan en CS:503F el tipo detectado, que luego es comparado en la rutina CS:01BA. Es ahí donde deberíamos interponer la llamada a esta subrutina olvidada. Pero hay algo más: si leemos la API de DPMI nos daremos cuenta de que la subrutina da por hecho que existe el DPMI y comienza por guardar los valores que devolvería la llamada para tantear la presencia del servicio, pero esta no aparece por ninguna parte. Una manera de rehabilitar esta opción, entonces, es desviar la llamada en CS:01EC hacia una rutina que haga:

mov ax, 1687h
int 2Fh
test ax, ax
je 1667 ;hay DPMI, llamo a la rutina
jmp 15B6 ;no pasó nada, sigo con lo que venía

Esto me permitió finalmente usar el debugger (bajo Windows 98), pero entre la lentitud con que funciona y una placa de video poco compatible, lo que parecía prometedor se redujo a pequeños avances: sólo adelanté en eliminar el cd-check, que no tenía nada de especial, excepto por la cantidad de checksums que lo protegen.

Entonces empecé a seguirle el rastro a las llamadas al MSCDEX, y encontré un patrón que me permitió ubicar la API de sonido en CS:98A0 y con ello los puntos en los que se silenciaba la música sintetizada: al volver al menú de selección de mesas, en el attract mode, y ante los eventos (mini juegos y fanfarrias al entrar en el marcador). Pero había algo en el modo de sortear este último caso que no me terminaba de convencer…

Las comparaciones no siempre son odiosas

Exultante por lo conseguido hasta acá, y con un panorama general de la situación en la cabeza, quería cerciorarme de que la solución fuera la correcta. Entonces recurrí al IDA (en su versión gratuita) para generar listados del código de las versiones en diskette y en CD, y poder así cotejar las diferencias en la rutina que me inquietaba. Después de algunas horas de concentración, apareció clarito ante mis ojos el punto ideal para evitar por completo toda la rutina adicional y disfrutar, ahora sí, del juego con toda su música.

Ya envalentonado le anulé también la rutina que grababa la configuración en un archivo externo y la necesidad de anteponer una barra (/) a las opciones (ver con ILLUSION ? la lista). Para terminar, restaba implementar el parche. En el stub, cuando estaba rehabilitando el DPMI, me crucé con el siguiente fragmento:

mov ah, 000h
int 094
call 1112 ;llamada inútil a un RET
call 1308 ;descompresión del juego en memoria

La primera llamada es la clave para intercalar las modificaciones al código. Invirtiendo el órden para que quede a continuación de la descompresión, nos queda un call libre para aplicar los cambios. Sólo debemos buscar un lugar no utilizado para escribir el parche y asunto terminado.

El resultado final de todo este trabajo puede aplicarse sobre cualquier versión original (i.e. no modificada) de Pinball Illusions CD, ya sea la de 1995 que ocupaba unos 50MB ó, mejor aún, la que se incluyó en las recopilaciones Pinball Power Pack y Pinball Gold Pack, que no están infladas y ocupan sólo 4MB, aproximadamente. Para eso, les dejo para descargar el parche completo. Un crack.

Pinball Illusions 20th Anniversary

Dedicado a Anita

Au revoir, Bonjour!

Después de desactualizar mi portátil nueva a Windows 7, llegó el momento de reinstalar las aplicaciones y otra vez la cuestión del insufrible iTunes: Instalarlo o no instalarlo, he ahí el dilema. Detesto el iTunes, el QuickTime y todas las porquerías innecesarias que instalan. Pero para leer, no he visto nada mejor que un iPad con pantalla Retina.

Lamentablemente, no hay hasta el momento alternativa al software oficial de Apple para gestionar el contenido de la tablita: los programas que se ofrecen como tales requieren invariablemente que se instale el iTunes para poder acceder al dispositivo. Así que descargué la versión 12 para Windows de 64 bits y me dispuse a tratar de instalarlo de la manera menos obstrusiva posible.

El primer paso fue extraer el contenido del instalador itunes6464.exe. De entrada vemos dos componentes que no queremos tener dando vueltas: AppleSoftwareUpdate.msi y Bonjour64.msi (sumémosle SetupAdmin.msi, ya que estamos). Probé hacer la instalación con las conocidas opciones DESKTOP_SHORTCUTS=0 MEDIA_DEFAULTS=0 y SCHEDULE_ASUW=0, pero sólo las dos primeras funcionaron. No es un gran problema, salvo para instalaciones desatendidas.

Buscando en el sitio de Apple llegué a la página donde explican cómo restringir ciertas opciones en Windows, entre ellas la búsqueda automática de actualizaciones y el acceso al iTunesStore. Con eso me di por satisfecho, así que instalé AppleApplicationSupport64.msi, AppleMobileDeviceSupport6464.msi e iTunes6464.msi, y creé la clave del registro para bloquear los componentes mencionados:

reg add "HKLM\SOFTWARE\Apple Computer, Inc.\iTunes\Parental Controls\Default" /v "AdminFlags" /t REG_DWORD /d "0x104" /f

Libre de otras criaturas despreciables, conecté mi iPad y ahí mismo se colgó el iTunes. Volví a abrirlo e intenté acceder a las preferencias, para ver si estaba seleccionado algún componente de los que quedaron afuera, pero eso también colgó al iTunes. Otras opciones, como reproducir música, funcionaban. Después de buscar sin éxito en la web, probé instalando el AppleApplicationSupport.msi y… ¡todo comenzó a andar! Ahora se entiende por qué la diferencia en los nombres de los componentes: los que tienen el sufijo «6464» parecen ser completamente de 64 bits, mientras que los que sólo dicen «64» dependen de los correspondientes componentes de 32 bits.

Para redondear, de los archivos extraídos del instalador, hay que conservar:

  • AppleApplicationSupport.msi
  • AppleApplicationSupport64.msi
  • AppleMobileDeviceSupport6464.msi
  • iTunes6464.msi

Y se puede agregar un archivo por lotes con lo siguiente:

msiexec /i "AppleApplicationSupport.msi" /passive /norestart
msiexec /i "AppleApplicationSupport64.msi" /passive /norestart
msiexec /i "AppleMobileDeviceSupport6464.msi" /passive /norestart
msiexec /i "iTunes6464.msi" /norestart
reg add "HKLM\SOFTWARE\Apple Computer, Inc.\iTunes\Parental Controls\Default" /v "AdminFlags" /t REG_DWORD /d "0x104" /f

Hablar bien no cuesta un carajo

Pocas cosas hay más útiles que un diccionario en la PC, siempre listo y a mano para sacarnos las dudas sobre el uso de tal o cual palabra. Por eso, saber que existe una versión del fabuloso Diccionario de uso del español de María Moliner para Windows me llenó de alegría.

Sin embargo, su interfaz no está libre de problemas. Una falla en particular hace que cada cierto tiempo se encapriche y nos pida que insertemos el CD de instalación, sin otra razón aparente que hacernos levantar para buscar el bendito disco y echar por la borda la comodidad de tenerlo instalado.

Montando una simple imagen del disco se resuelve el problema, pero molesto por lo chapucero de esa solución me decidí a ir al grano y darle masa al problema.

«Para nosotros, para nuestra posteridad…»

El diccionario (me refiero a la versión 2.14.1, que abunda en las redes P2P) fue escrito en Visual Basic 6.0, y aparentemente registra información sobre los accesos en archivos cifrados (00.SIG, 01.SIG y 10.SIG) que conservan su fecha del año 2001, para que no nos percatemos a simple vista cuando son actualizados. Todo muy lindo, pero es bastante fácil de pasar la protección por alto, como veremos a continuación. A pesar de todo, al día de hoy no hay un solo crack disponible; se ve que los diccionarios no son tan populares como el Call of Duty

Vamos a aprovechar esta ocasión para probar el VB Decompiler en su versión «Lite», que si bien carece de algunas características útiles de la versión «Pro» (como la posibilidad de aplicar parches), es gratuita y cubre ampliamente nuestras necesidades. Ni bien abrimos la herramienta, vamos a ‘Tools/Options’ y ahí tildamos la opción ‘Add HEX dump’ para que incluya las secuencias de bytes correspondientes a las instrucciones desensambladas, cosa que nos permitirá compensar la mencionada falencia de la versión «Lite». Vayamos a ‘File/Open program’ y seleccionemos DUE.EXE (el ejecutable principal del diccionario). Nos preguntará si queremos descompilar el programa ahora; cliqueamos en ‘No’ y nos vamos a tomar unos mates.

Un par de cebadas después, repetimos los pasos anteriores pero esta vez contestamos que sí a la pregunta del millón. Después de trabajar un ratito (el VB Decompiler; nosotros seguimos con el mate) nos avisará con el mensaje «Decompiled OK» que ha terminado. Tenemos a la vista un panorama general de la estructura del programa. Aquí nos conviene echar un vistazo para ver si algo nos resulta llamativo. Entre los módulos aparece uno llamado DUEProtection que parecía prometedor, pero sólo me hizo perder tiempo. Hagamos doble-clic sobre Sub_Main. Unas pocas líneas después del comienzo aparece la primera cosa realmente interesante: una llamada (call), una comprobación (test) y un salto condicional (jnz) que en caso de no producirse termina en una llamada a la rutina «End».

VB Decompiler screenshot
La llamada.

¿A dónde se dirige la llamada? La rutina 601DD0h se encuentra en el módulo WindowsModule, que ¡oh sorpresa! hace referencia a la cadena «Inserte el CD-ROM del DUE en el lector». Mi primer impulso fue cambiar el jnz (saltar si no es cero) por un jmp (saltar «sin peros»), remplazando el 75h por EBh en la instrucción 75C0 (ver pantalla). Para ubicar este segmento de código en el archivo DUE.EXE se necesita -además de un editor como WinHex o similar- encontrar una secuencia de bytes característica (que no se repita). Probando con la mismísima llamada a la rutina donde suponemos reside la protección (E8D9F40300) lo encontramos al toque. Es fundamental verificar que sólo aparezca una vez, para confirmar que estamos en el lugar indicado. Hacemos el cambio y probamos. La misma ventana de siempre: «Inserte el CD-ROM del DUE en el lector». Pero al darle ‘Cancelar’ en vez de cerrarse… ¡abre el diccionario!

Toque, gol y fiesta

Evidentemente estamos en el área chica. Sólo hay que afinar un poco la puntería y clavarla en el ángulo. ¿Qué es lo que está pasando? El salto que encontramos es el que lleva a la protección, y cuando vuelve le dice al programa principal si pusimos el bendito CD en la unidad o no. Entonces, hagamos al revés y eliminemos la llamada por completo. Volvemos a buscar la misma secuencia de antes y esta vez la «tachamos» con cinco 90h (que en ensamblador de intel significa ‘nop’, i.e. NoOPeration). Probamos nuevamente y… ¡entró como piña!

Antes de cantar la victoria total y definitiva, tenemos que ocuparnos de dos pequeños ayudantes: Conjugador.exe y Definidor.exe, que son invocados desde el acceso rápido del DUE. Si tratamos de utilizarlos, se repite la misma historia que con el diccionario. Si los desensamblamos, comprobaremos con disgusto que ambos tienen una serie de saltos que buscan claves en el registro y mil cosas más. Además, los módulos parecen tener los nombres desordenados; WindowsModule no es lo que esperábamos y el mensaje «Inserte el CD-ROM del DUE en el lector» aparece ahora en uno llamado DueServerPathModule. Pensemos un poco y apliquemos la Ley del menor esfuerzo.

La protección del programa principal hacía un salto a una rutina propia (call xxxxxxxxh), una comprobación (test) y un salto condicional (jnz). Busquemos «test» en el módulo Sub_Main de los ayudantes. Encontraremos tres o cuatro bloques con la siguiente estructura:

call MSVBVM60.DLL.__vbaFreeObj  ;llamada rutina VB
movsx ecx, word ptr var_C4
test ecx, ecx
jz 4077DBh

Pero uno solo de la forma:

call 0040F180h  ;llamada rutina propia
movsx ecx, ax
test ecx, ecx
jnz 407BD7h

De más está decir que este último es el salto a la rutina maldita, que dejaremos sin efecto tachándolo en ambos ayudantes con cinco 90h, como en el programa principal. ¡Ahora sí! Nuestro diccionario ha quedado completamente corregido y no volverá a obligarnos a levantar de la silla.

Destapate un PopCap

¿Quién no se ha pasado un par de horitas con algún juego de PopCap? Si nunca oiste hablar de Bejeweled, Hammer Heads o Zuma, date una vuelta por www.popcapgames.com y echá un vistazo a la sección «Juegos para descargar», de donde vas a poder bajarte una versión limitada de cualquiera de sus 49 juegos para PC.

Una hora más tarde, cuando haya expirado el tiempo de prueba, en vez de arrancarte los pelos, usá lo que tenés en la cabeza y seguí leyendo, que te explico cómo «sacarles la chapita» a estos juegos, usando como ejemplo al lanzamiento de hoy: Zuma’s Revenge.

Lo primero que tenés que hacer es descargar la versión de prueba (ZumasRevengeSetup-es.exe) y desempaquetarla con algún compresor de archivos. Yo uso WinRAR, pero cualquier otro puede servir. Vas a ver dos carpetas: cfg y files, y dentro de files está la única que nos interesa: Zuma’s Revenge.

Hacé doble-clic sobre la ranita para ejecutar el programa. Vas a ver el cartel que nos advierte que es una versión de prueba y que nos quedan 60 minutos de juego. Pulsá Jugar demo y una vez que haya terminado de cargar, pulsá Alt-Tab para volver al Explorador de Windows. Si no tenés activada la opción para poder ver los archivos ocultos y de sistema, activala desde Herramientas/Opciones de carpeta… En la solapa Ver, marcá «Mostrar todos los archivos y carpetas ocultos».

Carpeta de instalación
El ejecutable principal aparece…

Prestá atención al contenido de la carpeta del juego. ¿Notás algo? Claro, ¡hay un nuevo archivo ejecutable! Está ahí, medio lavadito (por ser un archivo oculto) con el nombre de popcapgame1.exe. A esta altura te imaginarás que éste es el verdadero ejecutable del juego, libre de toda limitación. Sólo tendríamos que copiarlo y listo. Pero hay un problema. El hecho de que no tenga un ícono puede significar dos cosas: o que no lo tiene (nunca hay que pasar por alto lo obvio), o que el sistema no puede acceder a él. Tratemos de copiar este archivo fuera de la carpeta; no podemos.

Si volvemos al juego y salimos a Windows, nuestro archivo habrá desaparecido. Entonces, ¿qué hacemos? El ejecutable de la ranita es en realidad el que nos impone las limitaciones de tiempo y nos impide acceder al verdadero ejecutable. Tenemos que deshacernos de él. Sin cerrar el juego pasemos al Administrador de tareas (Ctrl-Alt-Supr ó botón derecho sobre la barra de tareas).

Aplicaciones activas
Matar la aplicación no servirá.

Ahí veremos dos aplicaciones: el juego Zuma’s Revenge! y el Explorador de Windows (que como está apuntando a la carpeta del mismo nombre se llama igual, aunque su ícono nos permite distinguirlo). Si ordenamos finalizar la tarea, el juego se cerrará del mismo modo que si lo hubiéramos cerrado normalmente, y el ejecutable habrá desaparecido también. Esto se debe a que el sistema operativo le pide que se cierre («cerrate o te reviento»), y como el juego sabe lo que le conviene elimina el ejecutable principal y volvemos al mismo punto de antes.

La solución está en terminar el proceso, para que la protección no tenga tiempo de borrar nada. Pasemos a la solapa Procesos (obvio, ¿no?) y ahí veremos más claramente lo que está pasando realmente.

Procesos activos
En los procesos está la solución.

El proceso de nombre ZumasRevenge.exe es la protección (la «chapita»), mientras que el juego que está andando en memoria se llama -como ya vimos antes- popcapgame1.exe. Nótese la diferencia de recursos que utiliza cada uno. Marcá entonces ZumasRevenge.exe y pulsá Terminar. Ahora que volvemos al Explorador, nuestro éxito debería ser evidente: ¡la ranita ha recuperado su aspecto! (aunque sigue estando un poco pálida).

Para terminar, borremos el archivo ZumasRevenge.exe y «des-ocultemos» al popcapgame1.exe, al que -dicho sea de paso- deberíamos ponerle el nombre ZumasRevenge.exe, nomás para ser prolijos. Ahora podemos hacer doble-clic sobre la única ranita que nos queda y disfrutar del Zuma’s Revenge (o cualquier otro juego del catálogo PopCap) durante todo el tiempo que se nos dé la gana.

Instalar Windows Home Server desde USB

Windows Home Server está pensado como un servidor ciego, es decir, que no requiere monitor, teclado ni ratón para funcionar. Su administración puede gestionarse completamente a través de la red, mediante la consola diseñada para tal fin. Pero durante la instalación es necesario contar con una lectora de DVD, interna o externa. A pesar de no ser una opción contemplada de fábrica, con cualquier pendrive de unos 2GB se puede salir del paso sin problemas.

La clave está en el programa DiskPart que viene con Windows. Lamentablemente, la versión 5.1 que trae el XP no es suficiente, dado que ignora las unidades USB. Es por eso que necesitamos contar con una PC con Windows Vista o superior, o al menos con el disco de instalación, como veremos más adelante.

Arrancamos DISKPART.EXE y le indicamos las siguientes órdenes:

Diskpart>list disk
vemos las unidades conectadas
Diskpart>select disk #
# es el número asignado a nuestro pendrive
Diskpart>detail disk
verificamos que sea el disco correcto
Diskpart>clean
borramos todo (OJO: todo, todo…)
Diskpart>create partition primary
creamos una nueva partición
Diskpart>active
la activamos (para poder arrancar desde ahí)
Diskpart>format fs=fat32
le damos formato en FAT32
Diskpart>exit
nos fuimos…

Una vez hecho esto, sólo nos resta copiar el contenido completo del DVD de instalación a la raíz del pendrive, seleccionar el inicio desde un dispositivo USB, y listo.

Si usamos Windows XP, no todo está perdido. Tenemos que iniciar la PC con el disco de instalación de cualquier versión de Vista (¿Quién no tiene a mano un disco de Vista?, pregunto). Cuando aparezca el botón «Instalar ahora», pulsemos la opción «Reparar el equipo». En la lista de sistemas operativos «reparables» no va a aparecer nada (porque el disco de Vista no repara instalaciones de XP). Le damos «Siguiente», y elegimos «Símbolo de sistema». A partir de ahí, el procedimiento es el mismo, ya que, de hecho, se está ejecutando el entorno de preinstalación de Vista.