Photo by pawel szvmanski on Unsplash

Consiguiendo Acceso Premium en Aplicación Android — Ingeniería Inversa

En el artículo de hoy les demostraré cómo es posible conseguir acceso a la versión premium de una aplicación de Android mediante ingeniería inversa en donde extraeremos el código de la aplicación para luego detectar y aprovechar una incorrecta separación de concerns.


Introducción

Como bien sabemos cualquier aplicación que sea visible al usuario (aplicaciones de escritorio, mobile, páginas web, etc) exponen su código también. Es decir, tanto la lógica de la interfaz de una página web hasta un juego es totalmente decodificable. Esto es comprobable viendo que hoy en día existen mods de juegos y aplicaciones, por ejemplo WhatsApp Plus, alguien tuvo que extraer el código, leer y entenderlo, esto es lo que conocemos como ingeniería inversa.

from meme generator

Cabe destacar que existen técnicas como la ofuscación, que en resumidas cuentas hacen que el código desensamblado sea poco entendible, haciendo muy complicada la lectura del mismo.

Hoy nuestro objetivo es una aplicación de Android, la cual viene instalada mediante un APK (Android Application Package).

Presentación del problema

Primero que nada, vale la pena destacar que todo lo que demostraremos acá es de carácter educativo. Esta vulnerabilidad fue reportada al desarrollador y seguidamente actualizado, cerrando la brecha.

La aplicación se llama StayFree, que tiene como funcionalidad principal monitorear el tiempo de uso de distintas aplicaciones que previamente hayas asignado. Una aplicación con más de 100.000 descargas.

GIF de StayFree

Sin entrar mucho en la aplicación, podemos notar en el gif de arriba que la aplicación es gratis, pero ofrece ciertas funcionalidades que son pagas y además nos colocan ads en plena navegación.

La app tiene una ventana donde puedes pagar para obtener la versión premium. Y algo de ahí llamó mi atención. Tiene una opción para desbloquear la versión premium usando un código.

GIF de StayFree cupón

Lo curioso de todo, es que cuando introducimos un código la aplicación no hace ninguna llamada a red (pude darme cuenta por una app que monitorea el envío y recibo de paquetes). Al no hacer ninguna llamada a red quiere decir que está validando el código internamente en la aplicación y no delegando la funcionalidad a un servicio externo. Por lo tanto, podemos hacer ingeniería inversa al código de la aplicación para intentar decifrar el código que está esperando el formulario.

Descompilar la aplicación

Para poder hacer ingeniería inversa primero es necesario tener el código de la aplicación a través del APK. Existen varias herramientas populares que nos facilitan la tarea: apktool, jadx, dex2jar, classyshark, jd-gui, etc. Para este caso, usaremos jadx que nos proporciona una interfaz muy cómoda donde podemos seleccionar el APK para luego descompilarlo y mostrarnos el proyecto. Fácil, no ?

StayFree descompilado con jadx

La parte divertida, Ingeniería Inversa

Anteriormente, vimos que la entrada del código premium se encontraba en una ventana llamada Shop. Por lo tanto, lo más sensato es buscar alguna clase o actividad que este relacionado con esto.

Clase Shop

Como vemos, existe una clase Shop que extiende de e que si miramos en los imports import android.support.v7.app.e; , por lo tanto es una actividad y estamos donde debemos estar.

Lo siguiente sería encontrar la funcionalidad que verifica el código, por lo tanto tenemos que encontrar alguna lógica involucrada al botón que valida el código de la entrada. Aquí puedes visualizar el código de la clase Shop.

((Button) findViewById(R.id.button_shopEnterCode))
.setOnClickListener
(new OnClickListener() {
public void onClick(View view) {
Shop.this.c();
}
});

Observamos que un botón con el id button_shopEnterCode llama a una función o método c . Si buscamos la función en el mismo archivo vemos que es la encargada de desplegar el pop-up para introducir el código. La clave aquí es saber qué hace el botón de OK”.

button.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
if (Shop.this.d().equals(editText.getText().toString())) {
...
} else {
...
}
}
}

Como remarcamos, están comparando el código que introducimos con el retorno de una función llamada d .

Función d

Yeap! Aquí tenemos la función que retorna el código que buscamos, pero nos encontramos con this.b.k() que es una variable de la clase de Shop que tiene aspecto de string, por lo tanto tenemos que saber de dónde viene y qué valor tiene.

private com.burockgames.timeclocker.a.e b

Sabemos que el tipo de b viene de ese paquete, por lo que tenemos que navegar hasta ese paquete , ubicar a la clase e y la función k respectiva para saber qué retorna.

public String k() {
return this.a.getString("lastSentMailID", "123456");
}

Oh! Si sabes de Android esto parece familiar… Shared Preferences!
Traduciendo esto, estamos buscando el key lastSentMailID pero si no encontramos el key, por default entregamos el valor 123456 .

Como primer intento podemos usar el valor por default y sustituirlo en la función d en donde this.b.k() es llamado.

En mi caso, cree un nuevo archivo en java en donde la función main tiene la lógica con las sustituciones pertinentes.

Programa de prueba para obtener código

El código resultante es:
99610081020103210441056100898499610082072
(puede variar, debido a que la función genera el código tomando en cuenta la fecha actual)

Colocando código premium válido
Verificando funcionalidades premium

BINGOOO! Hemos conseguido un código válido y desbloqueado las funcionalidades premium 😎😎😎!!

Conclusión

Con un poco de tiempo y conocimientos en Android y Java es posible aplicar ingeniería inversa en cualquier aplicación de la Google Play. Por lo tanto como desarrollador hay que tratar de aplicar buenas prácticas y evitar delegar lógica sensible a las aplicaciones clientes. En este caso, la lógica de validación sobre un código la debería realizar un servicio externo (backend) donde solo hay acceso autorizado.

Por último, tratar de ser consiente con las herramientas mencionadas arriba teniendo un fin educativo y/o benéfico para el mundo.


Espero que hayas disfrutado el contenido, cualquier comentario, sugerencia u otro aporte es bienvenido.

También puedes encontrarme en Github, Twitter o LinkedIn.