Deshabilitar las comprobaciones de estado de tiempo de ejecución en una aplicación de Android



En un artículo anterior, hice una revisión sobre OWASP Mobile TOP 10 y luego no tuve un caso adecuado para demostrar la necesidad de proteger el código fuente. Un caso interesante para la demostración apareció recientemente y quién está interesado en ver nuestra experiencia de eludir los controles ambientales, veamos al gato.

Al evaluar el desempeño de uno de los proyectos, nuestro equipo se dio cuenta de inmediato de que el caso no sería fácil. Los desarrolladores abordaron bien el tema de la seguridad de la información en el programa e implementaron controles sobre el estado del entorno de ejecución. La aplicación no se inició bajo ninguna de las siguientes condiciones:

  • el dispositivo estaba en celo;
  • se usó un emulador;
  • disponibilidad de conexión a través de USB;
  • usando el modo desarrollador.

Los desarrolladores no ofuscaron el código fuente y no hubo una verificación integrada para la modificación del código, lo que me permitió analizar los métodos mediante los cuales se realizaron las verificaciones y realizar las manipulaciones necesarias con ellos.

Entonces comencemos. De acuerdo con OWASP Mobile TOP 10, que utilizamos como metodología de prueba básica en Hacken, Ingeniería inversa: esta vulnerabilidad incluye el análisis de archivos binarios para determinar el código fuente, bibliotecas, algoritmos, etc. Software como IDA Pro, Hopper, otool y otras herramientas de ingeniería inversa pueden dar una idea del funcionamiento interno de la aplicación. Esto se puede usar para buscar vulnerabilidades de aplicaciones, extraer información crítica como un servidor de fondo, claves de cifrado o propiedad intelectual.

Para realizar el análisis estático básico, utilicé una herramienta tan interesante como MobSF, que realizó la descompilación y el análisis estático básico. Después de la descompilación, me interesaron los códigos java y smali del programa. El código Java es necesario para el análisis, y realizaremos cambios en el código pequeño. Más detalles sobre cómo se relacionan smali y java se pueden encontrar aquí .

Después de mirar la lista de clases, encontré un archivo que es responsable de verificar la rutina del teléfono (ver Figura 1): rootingcheck / RootBeerNative.java.


Fig. 1. Lista de clases de aplicación

Después de analizar la clase, quedó claro que necesitamos buscar más a fondo las llamadas a las funciones checkForRoot () y setLogDebugMessage () (ver Figura 2).


Fig. 2. El código fuente de la clase para verificar rutovanost

Usando el comando grep, obtenemos los siguientes resultados, que nos muestran qué archivos contienen la llamada a los métodos checkForRoot () y setLogDebugMessage ().

Resultados de la búsqueda:
root @ kali: ~ / Desktop # grep -nr 'RootBeerNative' ******** _ v_0.9.2 /

********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:1:.class public Lrootingcheck/RootBeerNative; ********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:17: sput-boolean v0, Lrootingcheck/RootBeerNative;->?:Z ********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:28: sput-boolean v0, Lrootingcheck/RootBeerNative;->?:Z ********_v_0.9.2/smali/rootingcheck/RootBeerNative.smali:57: sget-boolean v0, Lrootingcheck/RootBeerNative;->?:Z ********_v_0.9.2/smali/o/CM.smali:591: new-instance v1, Lrootingcheck/RootBeerNative; ********_v_0.9.2/smali/o/CM.smali:593: invoke-direct {v1}, Lrootingcheck/RootBeerNative;-><init>()V ********_v_0.9.2/smali/o/CM.smali:685: new-instance v0, Lrootingcheck/RootBeerNative; ********_v_0.9.2/smali/o/CM.smali:687: invoke-direct {v0}, Lrootingcheck/RootBeerNative;-><init>()V ********_v_0.9.2/smali/o/CM.smali:689: invoke-static {}, Lrootingcheck/RootBeerNative;->?()Z ********_v_0.9.2/smali/o/CM.smali:753: new-instance v4, Lrootingcheck/RootBeerNative; ********_v_0.9.2/smali/o/CM.smali:755: invoke-direct {v4}, Lrootingcheck/RootBeerNative;-><init>()V ********_v_0.9.2/smali/o/CM.smali:764: invoke-virtual {v4, v3}, Lrootingcheck/RootBeerNative;->checkForRoot([Ljava/lang/Object;)I ********_v_0.9.2/smali/o/xZ$5.smali:257: new-instance v1, Lrootingcheck/RootBeerNative; ********_v_0.9.2/smali/o/xZ$5.smali:259: invoke-direct {v1}, Lrootingcheck/RootBeerNative;-><init>()V ********_v_0.9.2/smali/o/xZ$5.smali:261: invoke-static {}, Lrootingcheck/RootBeerNative;->?()Z 

root @ kali: ~ / Desktop # grep -nr 'setLogDebugMessages' ******** _ v_0.9.2 /
 ********_v_0.9.2/smali/o/CM.smali:599: invoke-virtual {v1, v0}, Lrootingcheck/RootBeerNative;->setLogDebugMessages(Z)I ********_v_0.9.2/smali/o/CM.smali:761: invoke-virtual {v4, v0}, Lrootingcheck/RootBeerNative;->setLogDebugMessages(Z)I 

Pero estos no fueron todos cheques. Después de analizar la clase MainActivity.java, encontramos llamadas a funciones donde se pasan las cadenas "su", "test-keys" y "which", con la ayuda de las cuales se realiza la verificación (ver Fig. 3).


Fig.3. Cheques de rutina

Y nuevamente, con el comando grep, buscamos en los archivos pequeños para verificar la rutina:

Resultados de la búsqueda:
root @ kali: ~ / Desktop # grep -nr 'su' ******** _ v_0.9.2 /

 ********_v_0.9.2/smali/o/CM.smali:443: const-string v2, "su" ********_v_0.9.2/smali/o/CM.smali:706: const-string v2, "su" ********_v_0.9.2/smali/o/xZ$5.smali:172: const-string v1, "su" ********_v_0.9.2/smali/o/xZ$5.smali:347: const-string v0, "su" 

root @ kali: ~ / Desktop # grep -nr 'test-keys' ******** _ v_0.9.2 /

 ********_v_0.9.2/smali/o/xZ$5.smali:141: const-string v1, "test-keys" ********_v_0.9.2/smali/o/xZ$5.smali:374: const-string v0, "test-keys" 


root @ kali: ~ / Desktop # grep -nr 'que' ******** _ v_0.9.2 /

 ********_v_0.9.2/smali/o/CM.smali:437: const-string v2, "which" 

En el artículo mostraré solo una de las modificaciones encontradas de las verificaciones de rutina. Después de una pequeña manipulación, es decir, cambiar de 1 a 0, se eliminaron las verificaciones de rutina.


Fig. 4. El valor de la variable es igual a uno si el teléfono está rooteado


Fig. 5. Ahora el valor de la variable es cero si el teléfono está rooteado

Después de eso, el programa se puede ensamblar, firmar con su clave de lanzamiento y ejecutar en un teléfono móvil. Pero si no fuera por dos PERO! A saber:

  1. Comprobación de conexión USB;
  2. comprobar la inclusión del modo desarrollador: la conexión USB y el modo desarrollador incluido permiten el análisis dinámico.

La verificación del modo Desarrollador se desactiva de la misma manera que la verificación de rutina, cambiando la unidad a cero en las verificaciones

En la clase MainActivity.java, encontramos la línea responsable de verificar el modo Desarrollador (ver Figura 6). Después de eso, busque los archivos en los que la cadena "development_settings_enabled" esté presente y modifique la comprobación: cambie 1 a 0 (consulte las Fig. 7 y 8).


Fig. 6. Compruebe si el modo de desarrollador está habilitado en el teléfono

Resultados de la búsqueda:
grep -nr "development_settings_enabled" ******** _ v_0.9.2 \

 Binary file ********_v_0.9.2\/build/apk/classes.dex matches ********_v_0.9.2\/smali/o/xZ$1.smali:49: const-string v1, "development_settings_enabled" 


Fig. 7. El lugar donde necesita realizar la modificación.


Fig. 8. Modificación

Después de todas las manipulaciones, puede ejecutar el programa en modo Desarrollador.

A continuación, apague la verificación de la conexión USB. Esta comprobación se encuentra en la clase MainActivity.java (consulte la Figura 9). Sin grep, encontramos la línea en MainActivity.smali, encontramos la línea que contiene la línea con la comprobación de USB: android.hardware.usb.action.USB_STATE. Después de eso, en el código smali, modificamos la línea a cualquier otro permiso que devuelva "falso" (ver Fig. 10).


Fig. 9. Verifique la conexión USB en el código MainActivity.java


Fig. 10. La línea de código que se eliminará en MainActivity.smali

Ahora le queda generar su clave de lanzamiento y firmar la aplicación con ella. Esto se hace de la siguiente manera:

  1. Necesita instalar dos aplicaciones: Keytool y Jarsinger.
  2. Ejecute el comando para ensamblar la aplicación:
  3. apktool b C: \ Users \ User \ Desktop \ ********
  4. Siguiente: cd ******** \ dist \
  5. Siguiente: Keytool.exe -genkey -alias key.keystore -keyalg RSA -validity 20000 -keystore key.keystore
  6. Siguiente: Jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore key.keystore ********. Apk key.keystore
  7. Siguiente: jarsigner -verify -verbose -certs ********. Apk

Aquí, en principio, todas las manipulaciones están terminadas. Ahora instalamos la aplicación en el teléfono usando adb install o desde el directorio de teléfonos inteligentes y puede realizar pruebas dinámicas de vulnerabilidad.

Después de instalar la aplicación, ejecútela (ver Fig. 11 y Fig. 12).

Fig. 11. Active el modo de desarrollador y conecte el USBFig. 12. Iniciando la aplicación

Conclusiones

En un ejemplo práctico, mostré cómo puede deshabilitar algunas comprobaciones sobre el estado del tiempo de ejecución. Además, con la ayuda de otras herramientas, realizamos un análisis de vulnerabilidad, pero esta es una historia diferente ...

Qué actitud negligente hacia la protección del código puede conducir a:

  • Estas son elusiones de ciertas comprobaciones que están integradas en el programa
  • implementación de código de terceros, después de lo cual el programa puede ser publicado y utilizado como malicioso

¿Cómo puedo protegerme? En ByteCode, decidimos no reinventar la rueda y sugerimos que el cliente ofusque el código fuente y use funciones que verifiquen la modificación del código fuente.

PS

Puede usar un método de análisis más avanzado: esta es una pequeña depuración. Puede leer más sobre esto en el manual .

Un poco como referencia, formulé una lista de líneas que se utilizan para verificar la rutina:

  • "Claves de prueba";
  • "/system/app/Superuser.apk";
  • "/ sbin / su";
  • "/ system / bin / su";
  • "/ system / xbin / su";
  • "/ data / local / xbin / su";
  • "/ data / local / bin / su";
  • "/ system / sd / xbin / su";
  • "/ system / bin / failsafe / su";
  • "/ data / local / su";
  • "/ su / bin / su";
  • "/ system / xbin / which";
  • "Su";
  • "Que".

Source: https://habr.com/ru/post/es419171/


All Articles