27 julio 2011

Androide 007 – Licencia para ejecutar



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.LicenseCheckerCallback)

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

14 comments :

SiD dijo...

Esto parece finales de los 80. Joder con el "nuevo mundo" de los smartphones y todo lo que lo rodea.

¿Quién dijo que no hay "nuevas oportunidades" de negocio? ;P

Raimundo Alcázar Quesada dijo...

Gran artículo Sebastián. Felicidades!!

Anonymus dijo...

Interesante entrada! Un consejo es qeu cambies la tipografia que aparece al insertar codigo fuente, se ve un poco mal! (en este caso la consola linux/mac)

Un saludo!

Juan Aguilera dijo...

Joer... no hay nada seguro. :D

Muy buen artículo, otros se hubieran centrado en el uso de anti-lvl y eso no tiene gracia. Me permito haceros un par de preguntas.

Una muy tonta pero que no la sé. ¿En qué lenguaje está el código que sustituyes?

Y la otra un poco más seria... ¿Qué soluciones alternativas hay de cara a los desarrolladores?

Anom dijo...

Excelente articulo. Pero he querido probar, y no me puedo bajar una aplicacion  para probar, hay que pagar antes, para la descarga. Entonce no podemos decir que los desarrolladores pueden estar mas que tranquilos? o es que uno es muy torpe-----

Teckel dijo...

Que si, que ya sabemos todos que es muy fácil PIRATEAR aplicaciones del market. Tampoco es que Google lo ponga muy difícil, y no lo hace porque no le da la gana: intenta luchar contra la PIRATERIA de las aplicaciones dando facilidades a los usuarios, no poniendo medidas anticopia la pera de avanzadas que:
1) Molestan a usuarios legítimos, empeoran el rendimiento de la aplicación y pueden causar problemas
2) Se romperán igual tarde o temprano.

Es decir, MUY BIEN para google, y respondiendo a la última pregunta del autor del artículo, LA CULPA ES DEL QUE LO PIRATEA, NI DE GOOGLE NI DEL DESARROLLADOR.

Las aplicaciones suelen costar 2-3 €, y comprándolas permites que muchos hackers (genios de los de verdad) sigan haciendo auténticas MARAVILLAS.

Eso sí, si alguien prefiere piratearlas para sentirse más inteligente que Google pues genial, pero que sepa que no ha hecho nada meritorio.

Juan Aguilera dijo...

Según saco del primer párrafo, es como saltarse la capa anticopia. El primero lo tiene que pagar pero después se puede saltar la protección para el resto. Por ejemplo para pasárselo a tus amigos sin pagar, o para otros destinos... La cuestión es que una vez saltada la protección cualquiera lo puede tener gratis.

Sebastián Guerrero Selma dijo...

Me alegro de que te haya gustado ;)!

El código es smali que no es más que una abstracción del bytecode nativo de Android. Si sabes manejarte bien con él, puedes pasarlo a Java e igualmente funcionará.
Como soluciones alternativas, la principal es no confiar sólo en las protecciones propuestas por Google, y que como desarrollador te implementes tus propios mecanismos de validación.

Sebastián Guerrero Selma dijo...

Gracias Raimundo, me alegro de que haya gustado!

Sebastián Guerrero Selma dijo...

Gracias! Tiene que haber algún embellecedor de código instalado como plugin, para la próxima lo tengo en cuenta :).

Sebastián Guerrero Selma dijo...

Como bien te ha contestado @google-60c8fb5994ecc6b9abf0327d1fa9d021:disqus se trata de un método para saltarte la capa anticopia.

El modo de operación que yo sigo cuando quiero hacer pruebas es el siguiente:

1) Tener una tarjeta válida y con saldo asociada a mi cuenta de usuario Google.
2) Realizar la compra de la aplicación.
3) Hacerme un backup de la aplicación para obtener el APK, normalmente con ASTRO puedes hacerlo.
4) Realizar el reembolso de la aplicación.
5) Trabajar con el backup y saltarme el anticopia.
6) Instalar la versión "liberada".

Sebastián Guerrero Selma dijo...

Evidentemente todos estamos de acuerdo en ese punto de que sistemas anticopia más avanzados lo único que van a lograr es dificultar la experiencia del usuario y la usabilidad de este con el teléfono.

Si te hubieras detenido a leer la entrada, te habrías dado cuenta de que en ningún momento se está incentivando a la piratería, yo soy el primero que cuando una aplicación realmente merece la pena la compro, y sino pues ni me molesto en piratearla, pero como proceso de investigación he querido dejar constancia de ello y contar que es posible y cómo se puede hacer.

No se trata de sentirse más inteligente que nadie, se trata de compartir lo aprendido.

Sebastián Guerrero Selma dijo...

Es evidente y estamos todos de acuerdo en que si Google decidiera añadir medidas de protección más restrictivas casi con toda seguridad empeoraría la usabilidad de los usuarios con sus dispositivos móviles.

En ningún momento en el post se incentiva el uso de la piratería, yo soy el primero que compra las aplicaciones si de verdad merecen la pena, y sino, ni me molesto en piratearlas, el tema ha sido compartir una investigación y comentar que es posible hacerlo y como. Aquí la finalidad está en las intenciones de cada uno.

Nadie trata en ningún momento de sentirse más inteligente que el resto, tan sólo se trata de compartir los conocimientos.

Juan Aguilera dijo...

Muchas gracias por tus respuestas. :)