Segunda contramedida: no usar la librería LVL estándar

Ejercicio paso a paso: Modificando la librería LVL.

En este ejercicio vamos a tratar de eliminar la comprobación de licencia de la aplicación desarrollada en el ejercicio anterior. Al no estar ofuscada podríamos decompilar el código a Java para estudiar mejor su contenido. Este paso nos lo vamos a saltar, dado que nosotros mismos hemos escrito este código.

1.     Desde Eclipse abre el proyecto ObtenciónLicencia.

2.     Accede al paquete com.google.android.vending.licensing y edita la clase LicenseCheckerCallback.

3.     Reemplaza la siguiente línea:

public void dontAllow(int reason);

Por:

public String dontAllow(String s, short reason);

No es necesario que cambies los identificadores; esto ya lo hará el ofuscador. Sería interesante cambiar también los otros métodos.

4.     Pon este método como el primero de la interfaz. Proguard no reordena los métodos automáticamente. Si no lo hacemos nosotros siempre se realizará el mismo cambio de nombre: el primer método àa(), el segundo àb(), etc.

5.     Añade otros métodos a la interfaz para despistar. Por ejemplo:

public String noHaceNada(String s, short reason);

 

6.     También es interesante cambiar los valores asignados a las constantes:

    publics tatic final int ERROR_INVALID_PACKAGE_NAME= 1;

    publics tatic final int ERROR_NON_MATCHING_UID= 2;

    publics tatic final int ERROR_NOT_MARKET_MANAGED= 3;

    publics tatic final int ERROR_CHECK_IN_PROGRESS= 4;

    publics tatic final int ERROR_INVALID_PUBLIC_KEY= 5;

    publics tatic final int ERROR_MISSING_PERMISSION= 6;

7.     Guarda esta clase. Como es de suponer aparecerán errores en otras clases.

8.     Edita la clase LicenseChecker y reemplaza la siguiente línea:

validator.getCallback().dontAllow(Policy.RETRY);

 

validator.getCallback().dontAllow("", (short) Policy.RETRY);

9.     Edita la clase LicenseValidator; encontrarás dos errores. Igual que antes añade "", (short) al principio de los parámetros.

10.     Edita la clase MainActivity; encontrarás dos errores. Para solucionar el segundo error reemplaza:

@Override public void dontAllow(int reason) {

Por:

@Override public String dontAllow(String s, short reason) {

Y añade al final de este método:

return r+reason;

Para solucionar el primer error, pon el cursor del ratón encima del nombre de la clase; se desplegará un menú. Selecciona Add unimplemented methods.

11.     Ejecuta la aplicación y comprueba que estos cambios no afectan en la verificación de licencia.

12.     Ofusca y firma la aplicación utilizando la opción File/Export…/Export Android Application. Se creará un fichero APK que has de copiar dentro de la carpeta place-apk-here-for-modding de APK Multi-Tool.

13.     Con esta herramienta decompila el código (opción: 9 Decompile apk).

14.     Verifica que el nuevo fichero m.smali ha cambiado: 

.class public interface abstract La/a/a/a/a/m;

.super Ljava/lang/Object;

# virtual methods

.method public abstract a(Ljava/lang/String;)Ljava/lang/String;

.end method

.method public abstract a(Ljava/lang/String;S)Ljava/lang/String;

.end method

.method public abstract a(I)V

.end method

.method public abstract b(I)V

.end method

En el ejercicio anterior se han realizado cambios bastante básicos. Para aumentar la protección se podrían plantear cambios más profundos. Por ejemplo, reemplazar el patrón de diseño Observador por otro mecanismo de comunicación. Es decir, en lugar de definir estos métodos callback, resolver la comunicación de otra manera. Por ejemplo, podrías hacer la variable permitir de tipo estático y modificarla directamente en la clase LicenseChecker, en lugar de llamar a los callback. Otra posibilidad podría ser lanzar un anuncio broadcast cuando se verifique la licencia.

Almacenar si tenemos licencia en una variable booleana parece algo sencillo de descubrir. Sería más interesante si cuando verificamos la licencia cambiamos algún aspecto de un objeto, de forma que sin este cambio la aplicación no funcionara correctamente.

Las medidas realmente efectivas serían cambiar el funcionamiento interno de la librería LVL. Por ejemplo en [1] se propone una implementación alternativa del método verify() de esta librería.

Práctica: Modificando más aspectos de LVL.

Trata de implementar alguna de las medidas que se han comentado en la explicación anterior. También puedes proponer alternativas en los foros de este capítulo