El objetivo de esta entrada es dar un pequeño repaso al funcionamiento de las medidas de seguridad propuestas por Google a la hora de establecer una capa anti copia (válida) en las aplicaciones de pago del Market y saltárnosla de forma manual y automatizada.

Cómo funciona la licencia

Abstrayéndonos un poco del funcionamiento interno, podemos distinguir tres componentes fundamentales:
  • La aplicación, que contiene el nombre del paquete y una llave firmadaque es utilizada para validar las peticiones por parte del servidor.
  • El cliente de Android Market, al tener más permisos que la aplicación
    se encarga de recoger la información necesaria acerca del usuario y el dispositivo (nombre de usuario en Google, IMSI, IMEI, etc...). Posteriormente envía la petición de verificación de la licencia al servidor en lugar de la aplicación.



  • El servidor evalúa toda la información recibida, comprobando la identidad del usuario con las solicitudes registradas de compra, devolviendo como respuesta la validez de la licencia que posteriormente es manejada por la aplicación del market.
Es decir, la idea básica reside en que el usuario como desarrollador puede querer establecer una serie de políticas de permisos que permitan comprobar en tiempo de ejecución si tenemos luz verde para poder ejecutar una aplicación o no en nuestro terminal.
Hay casos donde las funcionalidades se ven restringidas, quedando su uso limitado a un
número determinado de intentos, o durante un periodo de tiempo. Y otros sin embargo nos impiden realizar un uso funcional.

Resumiendo el proceso a nivel de código; se crea una instancia de:

com.android.vending.licensing.LicenseChecker

y esta es encargada de llamar al método:

checkAccess(com.android.vending.licensing.LicenseC heckerCallback)

que realiza la consulta y devuelve la respuesta llamando al método encargado de ejecutarla.


¿Hasta qué punto es segura?

El servidor firma las validaciones con un par de claves RSA que son compartidas exclusivamente entre el servidor y el desarrollador de la aplicación.

Posteriormente el servicio de licencias genera un par de claves para cada cuenta de editor y publica la parte pública en el perfil de la cuenta de usuario. Este copia la llave pública y la incrusta en el código fuente de la aplicación, la compila y publica el APK.

Mientras tanto el servidor que almacena la parte privada la utiliza para firmar las respuestas a las validaciones de licencia para cada aplicación publicada por el usuario.

Una vez se ha recibido una respuesta satisfactoria por parte del servidor, se procede a utilizar la llave pública para validar la integridad de los datos. De esta forma se evita cualquier tipo de manipulación en la respuesta. O eso es lo que espera Google.


Vamos a jugar un poco

Hoy en día existen diversas herramientas que realizan esta labor de forma totalmente automatizada librándonos de todo el proceso. En esta entrada nosotros vamos a realizarlo de las dos formas, manual y usando la aplicación (antilvl) desarrollada por Lohan Plus. Siempre viene bien conocer cómo funciona todo el proceso interno.

La aplicación que vamos a desproveer de su protección es "They need to be fed" un juego desarrollado por YoyoGames.


-- Proceso manual
Lo primero que debemos hacer es desempacar el fichero APK para obtener el classes.dex. Recordemos que ahí es donde está contenido todo el código de nuestra aplicación. Aquí podemos tomar varios caminos y transformar el fichero contenedor de las clases a código Java, instrucciones Dalvik o realizar una interpretación del mismo usando baksmali, entre otras.

Nosotros haremos esto último, así que nos apoyaremos en la herramienta baksmali (v1.2.6):

sebas@Helios:~/Android/research/protection/com.yoyogames/bcode/com$ java -jar baksmali-1.2.6.jar -x -o baksmali_code ../../Android/research/protection/com.yoyogames/classes.dex

Una vez tenemos a nuestra disposición el código, el siguiente paso es buscar el fichero donde está contenida la comprobación de la licencia:

sebas@Helios:~/Android/research/protection/com.yoyogames$ find ./baksmali_code/ -name "LicenseChecker.smali"

./baksmali_code/com/android/vending/licensing/LicenseChecker.smali

Ese fichero contiene dos métodos cuyo código es necesario modificar para cumplir nuestro objetivo, el primero es el "checkAccess" (código aquí) que básicamente se encarga de comprobar si tenemos suficiente acceso como para usar la aplicación.

sebas@Helios:~/Android/research/protection/com.yoyogames.droidtntbf-1.apk_FILES$ grep -Hnr "checkAccess" .

Coincidencia en el archivo binario ./classes.dex
./baksmali_code/com/yoyogames/droidtntbf/RunnerActivity.smali:335: invoke-virtual {v1, v2}, Lcom/android/vending/licensing/LicenseChecker;->checkAccess(Lcom/android/vending/licensing/LicenseCheckerCallback;)V
./baksmali_code/com/android/vending/licensing/LicenseChecker.smali:627:.method public declared-synchronized checkAccess(Lcom/android/vending/licensing/LicenseCheckerCallback;)V

Y el segundo el "handleServiceConnectionError" (código aquí), que se encarga de generar las respuestas ante incidentes de errores de conexión con el servicio, véase timeouts, por ejemplo.

sebas@Helios:~/Android/research/protection/com.yoyogames$ grep -Hnr "handleServiceConnectionError" .

Coincidencia en el archivo binario ./classes.dex
./baksmali_code/com/android/vending/licensing/LicenseChecker.smali:168: invoke-direct {p0, p1}, Lcom/android/vending/licensing/LicenseChecker;->handleServiceConnectionError(Lcom/android/vending/licensing/LicenseValidator;)V
./baksmali_code/com/android/vending/licensing/LicenseChecker.smali:464:.method private declared-synchronized handleServiceConnectionError(Lcom/android/vending/licensing/LicenseValidator;)V
./baksmali_code/com/android/vending/licensing/LicenseChecker.smali:615: invoke-direct {p0, v1}, Lcom/android/vending/licensing/LicenseChecker;->handleServiceConnectionError(Lcom/android/vending/licensing/LicenseValidator;)V
./baksmali_code/com/android/vending/licensing/LicenseChecker.smali:774: invoke-direct {p0, v0}, Lcom/android/vending/licensing/LicenseChecker;->handleServiceConnectionError(Lcom/android/vending/licensing/LicenseValidator;)V

Una vez identificados sustituimos el código del método "checkAccess" por este, y el de "handleServiceConnectionError" por este otro.

Básicamente lo que hacemos es meter un par de mensajes en el log para facilitarnos un poco la tarea con logcat a la hora de hacer la traza a la ejecución de la aplicación, y por otro lado nos aseguramos de que se esté llamando al método allow().



El siguiente paso es firmar la aplicación para poder instalarla en nuestro dispositivo, esto se hace en unos sencillos pasos:
  • Generamos nuestra clave privada:

    sebas@Helios:~/Android/research/protection$ keytool -genkey -v -keystore llave-poc.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000

    Empacamos el APK, puedes usar apktool para esta tarea.
  • Firmamos con jarsigner:

    sebas@Helios:~/Android/sdk/tools$ jarsigner -verify -verbose -certs ~/Android/research/protection/com.yoyogames/prueba.apk

  • Utilizamos zipalign:

    sebas@Helios:~/Android/sdk/tools$ ./zipalign -v 4 ~/Android/research/protection/com.yoyogames/prueba.apk ~/Android/research/protection/com.yoyogames/prueba-final.apk
Y listo, si la instalamos veremos que hemos conseguido saltarnos la verificación de pago.

-- Proceso automatizado

Si queremos evitarnos el engorro de todo el proceso podemos usar anti-lvl, una herramienta desarrollada por Lohan Plus cuyo principal propósito es revertir el "License Verification Library" (LVL) y cualquiera de sus implementaciones. Además en cada versión se añaden nuevas huellas de las distintas variaciones existentes, con lo que al estar en constante actualización proporciona la seguridad de alcanzar el objetivo que perseguimos.

El uso más sencillo no puede ser, y con una simple línea consigue hacer todo el proceso por nosotros, basando su proceso en sencillos pasos: desensamblado, detección de los mecanismos de protección, eludir los mecanismos, ensamblar, firmar, y hacer el align a los primeros bytes:

sebas@Helios:~/Android/sdk/tools$ sudo java -jar antilvl.jar -f ~/Android/research/protection/com.yoyogames.droidtntbf-1.apk pruebafinal.apk



Si ahora pasamos esa aplicación a nuestra SDCARD y la instalamos, obtendremos el mismo resultado que comentábamos con anterioridad.

Conclusión

Una vez más queda demostrada la facilidad con la que es posible ownear a Google. En este caso la seguridad que proporcionan a sus aplicaciones. Supongamos la situación de que una empresa decide desarrollar uno de sus productos para plataformas Android, esta aplicación debe de pasar previamente por el market, así que deciden aprovechar la funcionalidad que Google ofrece de aplicar el LVL y así asegurarse de que nadie pueda utilizarla sin antes pagar el precio que tiene.

Supongamos que estamos hablando de una conocida empresa que fabrica aplicaciones con finalidad de Navegador/GPS, y que tienen un precio de 70€. Ahora vamos y nos burlamos de ese sistema de seguridad y la tenemos gratis en nuestro dispositivo.

¿A quién se le echa la culpa, al desarrollador por no haber tomado las suficientes precauciones y haber confiado en Google, o a Google por tener un sistema tan infalible?



Contribución por Sebastián Guerrero