Estoy seguro que la mayoría que tenga WhatsApp le gustaría que sus contactos no supiesen cuando estás conectado a él, no son pocos los que envían un mensaje y para saber si lo han leído o no abren de cuando en cuando WhatsApp y ven el estado de conexión del otro para ver cuando fue la última vez que se conectó. Personalmente me da exactamente igual que lo vean o no, pero seguro que la mayoría piensa de otro modo.

Como con la gran mayoría de todos los experimentos, este me llegó después de que un amigo me dijese que su hermano había comprado una aplicación de Android para impedir que sus contactos pudiesen conocer la última vez que estuvo conectado al WhatsApp. Bueno en Android ya sabemos que técnicamente el Ultima vez conectado no es propiamente eso, sino cuando fue la última vez que el usuario tenía en primer plano la aplicación WhatsApp, puesto que en realidad el usuario está siempre conectado. Sabemos que los usuarios de iPhone tienen una opción para deshabilitar esto, los conocemos bien porque son aquellos contactos en los que cuando vemos su estado simplemente no aparece ninguna fecha. En Android no tenemos esta opción, pero eso no quiere decir que no pueda modificarse la aplicación para crear un comportamiento parecido, o incluso mejor.

En realidad este pequeño experimento es solo un ejemplo de la gran utilidad que tiene la Ingeniería Inversa. Pese lo que puedan pensar muchos programadores o defensores a ultranza del código propietario, la Ingeniería Inversa permite conocer mejor el software, descubrir problemas de seguridad para evitarlos, crear Software de mejor calidad… no es una lacra ni un problema, todo lo contrario, es una gran herramienta.

Volviendo al tema de hoy, cuando me dijo este amigo mío sobre dicha aplicación en Play Store sinceramente me extrañó, por la simple razón de que si es un comportamiento de la aplicación en sí, la única forma de eludirlo sería con una modificación de la misma aplicación… a menos que se tratase de un simple truco. Efectivamente, lo que hacen este tipo de aplicaciones no es más que un truco para provocar un efecto similar que puede realmente funcionar bastante bien, aunque tiene muchos problemas asociados sin duda alguna. Para saber en que se basan estas aplicaciones para esconder el estado de conexión de nuestro terminal hay que conocer antes como maneja WhatsApp dicho estado, no hay que profundizar mucho, en realidad es muy sencillo:

La primera cosa que hay que tener clara de nuevo es que en Android las aplicaciones se minimizan, no se cierran (pueden cerrarse también, pero vamos a simplificarlo), esto es debido a que Android es multitarea. Aunque WhatsApp no esté en primer plano continua en ejecución, lo que quiere decir que cualquier mensaje que nos manden, imagen… la recibimos perfectamente en nuestro terminal en ese mismo momento, el que volvamos a poner a WhastApp al primer plano no cambia nada. Teniendo esto en mente, cuando el usuario abre la aplicación o la coloca en primer plano estando minimizada, WhatsApp envía a los servidores de estos un mensaje sobre su estado de forma peródica y constante. Cuando el usuario minimiza la aplicación, este desactiva este comportamiento, con lo que de cara a cualquier otro usuario nuestro estado de conexión cambiará de “En línea” a “Últ. Vez”.  Conocer esto no requiere realmente ser un experto en nada, estoy seguro que muchos que se hayan planteado el “como funcionará…” habrá echo sus propios experimentos de cuando cambia el estado y otras cosas.

Sabiendo por tanto como es el comportamiento de WhatsApp, cualquiera podría imaginar como engañar a WhatsApp, repito, simplemente conociendo como funciona el cambio de estado. Se trataría simplemente de evitar que WhastApp comenzase a enviar esos mensajes a su servidor, y lo cierto es que tenemos una solución muy sencilla a esto, no tener conexión. El no tener conexión (ni WIFI ni datos) impediría evidentemente que WhatsAppe comenzase a enviar los mensajes de estado, pero evidentemente también impediría que WhatsApp pudiese mandar cualquier cosa a otro contacto o recibir mensajes o cualquier otra cosa, pero como ya hemos dicho WhatsApp aun estando minimizado se está ejecutando, y sabemos que el cambio de estado solo sucede cuando tenemos la aplicación en primer plano, es decir la maximizamos. Aplicando la lógica común, nos bastaría tan solo con deshabilitar datos/wifi cuando queremos volver al WhatsApp para escribir un mensaje o leer alguno ya recibido, y volver a conectar los datos/wifi cuando la minimizásemos de nuevo. Estando minimizada y con conexión, recibiría perfectamente mensajes o imágenes o cualquier otra cosa, así como también enviaría nuestros mensajes escritos a nuestros contactos, pues estarían a la espera de conexión.

Esto que he explicado puede hacerlo cualquiera en su casa en cualquier momento, y de echo funciona perfectamente, aunque por supuesto tiene muchos problemas. Las aplicaciones que están en Play Store simplemente automatizan este proceso, pero hacen exactamente lo que he indicado. Hacen que cuando se maximiza (se cambia a primer plano) WhatsApp, se deshabilitan datos y wifi, y se invierte cuando se minimiza WhatsApp. Muchos pueden pensar que es la solución perfecta, pero no solo no es perfecta puesto que no funcionaría siempre, sino que además el usuario perdería mucha funcionalidad en el WhatsApp. Por ejemplo, para mantener una conversación con alguien tendría que estar minimizando y maximizando constantemente puesto que de lo contrario sus mensajes no se enviarían ni el podría recibir nuevos mensajes! Para un mensaje ocasional funcionaría, pero si esa persona quisiese mantener una conversación mínima con cualquiera, tendría que mandar mensaje, minimizar, esperar que el otro respondiese, maximizar, escribir, minimizar.. es evidente que no es práctico de ninguna de las maneras, sin contar que lo único que el usuario podría descargar serían imágenes si tuviese activado el autoaceptar, el resto de contenido no podría descargarlo nunca.

¿Es posible dar con una solución más eficaz? Sí, ingeniería inversa. En el artículo que menciono justo abajo explico mejor que es la Ingeniería inversa para quien no lo conozca, pero digamos que en el software es básicamente el proceso de obtener información sobre como funciona una aplicación de forma interna sin disponer su código fuente original, lo que nos permite incluso modificar la aplicación misma. Recordar que en algunos países la ingeniería inversa es ilegal, aquí en España es legal siempre y cuando no se distribuya su código o cualquier modificación realizada. Es por eso que aunque puedan pedirlo algunos, no puedo colgar ningún WhatsApp modificado lo siento, cada cual que experimente si así lo desea, además la razón de este blog ha sido siempre para enseñar, no para dar.

 

 Muchos de los pasos realizados aquí, los encontramos también en otro artículo que publiqué hace ya meses. En Android, cualquier proceso de Ingeniería inversa tendría los mismos pasos a seguir:

  1. Obtener la aplicación APK (y el paquete odex en caso de ser una aplicación interna de algunos terminales)
  2. Decompilar la aplicación para obtener el código Dalvik equivalente.
  3. Realizar las modificaciones pertinentes.
  4. Recompilar la aplicación, firmarla y alinearla (optimizarla).

Con excepción al paso 3º, el resto son siempre los mismos, existiendo tan solo pequeñas modificaciones entre diferentes casos, pero nada importante. Como tales procesos están explicados en el artículo mencionado, simplemente voy a presuponer que se saben realizar. Existen herramientas incluso que nos permiten obtener un código en JAVA relativamente fidedigno desde la aplicación APK, que aunque no pueda ser recompilado, al menos será mas inteligible para la mayoría de las personas que lo es el código en Dalvik

Obtener por tanto un código que podamos modificar es simple una vez se decompila la aplicación, por ejemplo con apktool. Así que vamos a presuponer que disponemos del código ya decompilado en la carpeta “whats”, y con eso completaríamos los pasos 1 y 2.

El tercer paso sería el más tedioso, puesto que de cientos de archivos que disponemos hay que saber que se quiere modificar, donde hacerlo y como hacerlo. En realidad es lo complicado del caso. En nuestro caso ya sabemos que queremos modificar, queremos suprimir el estado de conexión de nuestro WhatsApp, pero seamos coherentes, tenemos una carpeta con el código decompilado que pesa más de 40MB y contiene más de 4000 archivos. Evidentemente tenemos que acotar nuestra búsqueda, o podríamos tardar años. A este problema se le suma el echo de que inevitablemente tenemos que conocer algo de programación en Android y de como funciona Dalvik, de lo contrario es imposible que pudiésemos encontrar el lugar (o lugares) en el que se implementa dicho comportamiento o como se tendría que modificar. Por suerte para nosotros, el código Dalvik resultante de la compilación es bastante más legible que el código ensamblador de la arquitectura x86. Dalvik es una máquina virtual basada en registros, y en el mismo código podemos ver por suerte la llamada a las funciones que son usadas, así como los parámetros pasados. Esto es una ayuda infinita sin duda, ya que simplemente con conocer a grandes rasgos el SDK de Android, podemos empezar a buscar lo que deseamos.

En nuestro caso concreto, presuponiendo que tan solo tenemos la idea que mencioné al principio de como/cuando se actualiza el estado de conexión, tendríamos que comenzar por ahí. Lo primero que sabemos es que nuestro estado cambia al volver WhatsApp al primer plano, es decir, en el código tiene que existir algún disparador que se acciona al realizar este cambio de estado en la aplicación. Cualquiera que le guste la programación en Android o simplemente haga un poco de investigación, antes o después encontraría esta imagen en la documentación oficial de Android:

actividad

 

Por supuesto existe documentación extensa sobre todo ello en el portal oficial, pero esta imagen es suficiente. Lo que nos dice esta imagen es que existen funciones concretas que son disparadas cuando nuestra aplicación cambia de estado, ya sea al iniciar la aplicación, al empezar a ejecutarse, al “resumirse”, al pausarse, al pararse, cerrarse, reiniciarse… lo cierto es que tenemos unas cuantas opciones. Si fuésemos un poco curiosos, también sabríamos que la función exacta que se dispara cuando una aplicación pasa de segundo plano a primer plano (maximizarse) se llama OnResume(), y la función que se aplica al pasar de primer plano al segundo es onPause(). Estos nombres pueden causar un poco de confusión ya que en realidad una aplicación en Android no se pausa propiamente dicho, pero obviemos esto.

Es evidente que una aplicación puede tener otros sistemas para detectar si la aplicación se encuentra en primer plano o no, pero siempre hay que partir de presunciones y ver a donde nos llevan, si son un callejón sin salida hay que volver y replantarse el problema para optar por otras opciones. Pero si WhatsApp está usando realmente onResume() para la actualización de nuestro estado, al menos podríamos ser capaces de realizar una gran criba. Así pues, si nos basamos en esta teoría, podríamos usar el comando findstr (en windows) o grep (en linux) para buscar dicha función dentro del código Dalvik, puesto como he dicho el nombre de las funciones se encuentran en él:

E:\Android\Proyectos\Whats>findstr /S /I /M onResume *.*
smali\com\whatsapp\AccountInfoActivity.smali
smali\com\whatsapp\BlockList.smali
smali\com\whatsapp\ContactInfo.smali
smali\com\whatsapp\ContactPicker.smali
smali\com\whatsapp\Conversation.smali
smali\com\whatsapp\Conversations.smali
smali\com\whatsapp\DeleteAccount.smali
smali\com\whatsapp\DeleteAccountConfirmation.smali
smali\com\whatsapp\DescribeProblemActivity.smali
smali\com\whatsapp\DialogToastActivity.smali
smali\com\whatsapp\DialogToastListActivity.smali
smali\com\whatsapp\EULA.smali
smali\com\whatsapp\GroupChatMap.smali
smali\com\whatsapp\LocationPicker.smali
smali\com\whatsapp\MediaGallery.smali
smali\com\whatsapp\MultipleContactPicker.smali
smali\com\whatsapp\OverlayAlert.smali
smali\com\whatsapp\RegisterName.smali
smali\com\whatsapp\RegisterPhone.smali
smali\com\whatsapp\Settings.smali
smali\com\whatsapp\VerifyNumber.smali
smali\com\whatsapp\VerifySms.smali
smali\com\whatsapp\ViewSharedContactActivity.smali
smali\com\whatsapp\wallpaper\CropImage.smali
smali\com\whatsapp\wallpaper\WallpaperPicker.smali

Simplemente con esto, si realmente WhatsApp usa dicha función para el cambio de estado, estaríamos restringiendo la búsqueda de más de 4000 archivos a 25 posibles lugares, en los cuales puede ser por supuesto más de uno. 25 es un número suficientemente manejable como para ir buscando en cada archivo manualmente, pero no soy un sádico y vamos a acotarlo aun un poco más. Con poco de inglés que sepamos y aplicando un poco la lógica común, podríamos cribar estos 25 resultados desechando aquellos que parecen no tener absolutamente nada que ver con la actualización del estado, ya que el listado anterior simplemente nos dice donde se está usando dicha función, pero evidentemente dicha función se usa para muchas cosas, no solo modificar supuestamente el estado:

smali\com\whatsapp\AccountInfoActivity.smali
smali\com\whatsapp\DialogToastActivity.smali
smali\com\whatsapp\DialogToastListActivity.smali
smali\com\whatsapp\ViewSharedContactActivity.smali

La razón por la que he suprimido los anteriores no está basado en que evidentemente antes de escribir estas letras ya sé que modificar o buscar, sino en el sentido común. Si tengo un archivo llamado WallPapperPicker, es de suponer que el punto exacto que estoy buscando no se encuentra en él. Por supuesto, de nuevo se está simplemente presuponiendo, esta aseveración podría ser errónea y llevar a un camino sin salida, con lo que de nuevo tendríamos que dar marcha atrás, aumentar el campo de búsqueda y ver si hay mas suerte.

Por experiencia y por el nombre de los archivos, automáticamente habría optado de los 4 archivos mencionados por el segundo y el tercero, DialogToastActivity y DialogToastListActivity, puesto que precisamente lo que quiero es inhibir el estado de conexión, el cual se refleja en lo que en ingles podría llamarse “toast”. Si esos dos archivos no me diesen la solución que busco, buscaría en los otros dos. En este caso concreto, lo que se busca está exactamente en el archivo DialogToastListActivity.

Este archivo podemos editarlo con cualquier editor de texto, y por suerte es un archivo pequeño, unas 670 líneas. Si buscamos por onResume, vemos que nos lleva a la línea 600 aproximadamente, y vemos que comienza un pequeño bloque de unas 25 líneas en Dalvik, algo sinceramente bastante pequeño. Llegado a este punto llegaría la segunda parte complicada, que punto modificar y como, a lo mejor basta con eliminar, a lo mejor se requiere modificar o quizás es añadir. Esto ya es más complejo porque implica tener conocimientos de Dalvik, que aunque es bastante sencillo hay que entenderlo. En este caso concreto podemos hacer alguna chapuza rápida que funcione relativamente bien, para no tener que entrar en muchos detalles.

Si leemos el bloque, vemos que en un momento dado se llama a la función onResume, y después de ello la siguiente función que se invoca de forma clara es sendEmpyMessageDelayed. Posiblemente la mayoría de programadores de Android conocen dicha función, y quien no la conozca puede buscar información al respecto, pero básicamente lo que hace esa función es enviar un mensaje cada X milisegundos, y aquí la palabra mensaje adquiere un amplio significado.

El pedazo de código que nos interesa sería por tanto:

    .line 8
    iget-object v0, p0, Lcom/whatsapp/DialogToastListActivity;->d:Lcom/whatsapp/jd;
    const/4 v1, 0×0
    const-wide/16 v2, 0xbb8
    invoke-virtual {v0, v1, v2, v3}, Lcom/whatsapp/jd;->sendEmptyMessageDelayed(IJ)Z
    .line 2
    const/4 v0, 0×1

En java, todo ello equivaldría más o menos a:

d.sendEmptyMessageDelayed(0, 3000L)

En Android sería algo así como enviar el mensaje ’0′ cada 3 segundos desde que la aplicación se resuma. Si estamos en lo cierto y todas las presunciones son ciertas, que pasaría por tanto si elimino dicho bloque?? En realidad en Dalvik hay que tener mucho cuidado porque es un lenguaje basado en registros, con lo que no suele ser bueno eliminar asignaciones a registros, puesto que quizás la línea que esté más abajo use el mismo registro para otra cosa, y si la asignación se elimina tendremos problemas. Por tanto podríamos limiter la eliminación a la línea:

invoke-virtual {v0, v1, v2, v3}, Lcom/whatsapp/jd;->sendEmptyMessageDelayed(IJ)Z

Si eliminamos esa simple línea, y todo lo que hemos dicho se cumple, al resumir la aplicación nunca se comenzaría a enviar el mensaje de actualización de cambio de estado (o lo que sea que contenga en ese punto los mensajes ’0′). La pregunta es si realmente ese es el punto exacto, o si dicha modificación posee efectos no deseados. Pero para eso la única opción posible es recompilar la aplicación con el cambio realizado y probarlos.

 

En este caso concreto, veríamos que efectivamente simplemente por eliminar dicha línea y recompilando el código, funcionaría perfectamente. No obstante tendría dos efectos secundarios no deseables, aunque serían “mínimos”. Realizando dicho cambio nunca veríamos si el contacto con el que hablamos está o no conectado en ese mismo momento, así como que tampoco nos aparecería el “Está escribiendo…”, pero nada más, todo lo demás funcionaría perfectamente. Este problema es debido a que el mensaje ’0′ que se envía cada 3 segundos no solo contiene nuestro estado de conexión. Por supuesto que esto puede ser perfeccionado y mejorado para suprimir tan solo nuestro estado de conexión.

Otra aplicación práctica de todo ello sería por ejemplo suprimir el envío de “Está escribiendo…” de forma que el contacto con el que hablamos nunca pueda saber si estamos escribiendo o no, lo cual implicaría por ejemplo eliminar un par de líneas en el archivo App.smali sin ningun otro efecto secundario. Podría aplicarse también para producir el efecto opuesto, aparentar estar siempre en línea, o incluso crear en las opciones un botón para habilitar o deshabilitar la actualización de estado a voluntad. En realidad no hay límites, simplemente hay que pensar que deseamos hacer e implementarlo.

conexion

Esa imagen está tomada desde otro WhatsApp el día 9 de febrero mientras ambos mantenían una conversación, en el estado vemos perfectamente que la última vez de conexión de Theliel (Alma Oscura) fue el 30 de Enero, contacto con el que además se estaba hablando en ese mismo momento, con lo que tendría que poner en línea de echo.

 

 Un saludo, y disfrutar de la invisibilidad de WhatsApp.