La cantidad de nuevas variantes de malware para Android que son descubiertas mensualmente no deja de crecer año a año y, paulatinamente, los desarrolladores de códigos maliciosos móviles comienzan a incorporar técnicas de evasión en Android para complicar la detección y rápida respuesta de compañías de seguridad.

Mientras los ciberdelincuentes descubren la eficacia en la propagación de amenazas móviles en mercados oficiales, la utilización de código antianálisis deja de ser la excepción para volverse la norma. Una de estas técnicas es la antiemulación, que puede representar un gran dolor de cabeza para los analistas. Por suerte, existen formas de evadir este tipo controles y en esta publicación veremos algunas.

Xposed y Android Blue Pill

La antiemulación es una metodología que busca identificar atributos particulares en emuladores y máquinas virtuales móviles para identificar si el entorno de ejecución corresponde o no a un dispositivo real. Puede ser implementada de diversas maneras comparando alguna propiedad del entorno contra un valor conocido: estructura del sistema de archivos, atributos de la placa de red, conectividad de telefonía móvil, datos del sistema, etcétera. Algunas de estas comprobaciones pueden verse reflejadas en el antiemulador desarrollado por Tim Strazzere.

En Github podremos encontrar varios proyectos que intentan evadir métodos antianálisis. Uno de ellos es HideAndroidEmulator: un módulo disponible para Xposed que realiza hooks a los métodos invocados por la aplicación y se encarga de parchear cualquier característica que pueda delatar la ejecución del emulador.

Este mismo módulo es utilizado por CuckooDroid para enmascarar la VM de análisis dinámico, aunque presenta algunas modificaciones y ha sido renombrado Android Blue Pill. Esta nueva versión puede ser descargada desde este enlace.

img_01

Si echamos un vistazo al código de Android Blue Pill podremos darnos una idea de cuál es el alcance del módulo, para así poder modificar el código a voluntad según lo que se necesite en cada caso.

img_02

Dentro de la funcionalidad que encontramos parcheada tenemos la siguiente:

  • Monkey: se hookea el método isUserAMonkey retornando siempre false, de modo que la muestra no pueda saber si se está utilizando adb shell monkey para detonar comportamientos.

img_03

  • Datos del build: cada vez que se llama el método onCreate de la clase android.app.Application la aplicación devuelve a cualquier proceso no conocido información personalizada del build del sistema.

img_04

También se hookea la clase android.os.Build, de modo que cada vez que se solicite la propiedad ro.product.brand el módulo retornará la cadena de texto “google” en vez de “generic”.

img_05

  • TaintDroid: Oculta funcionalidad específica de TaintDroid al encubrir la clase dalvik.system.Taint.

img_06

  • Ficheros del emulador: oculta la existencia de archivos necesarios para la operación del emulador que no se encuentran en dispositivos reales, forzando el retorno de false en el método exists de java.io.File siempre que la ruta pasada por parámetro esté almacenada en el array de rutas predefinidas por el analista.

img_07

  • Batería: simula el funcionamiento de una batería al modificar el valor de la carga tras recibir un intento del tipo android.intent.action.BATTERY_CHANGED.

img_08

  • IOBinder: a través de un hook al método open de libcore.io.IoBridge, Android Blue Pill retorna falsas rutas para archivos que contienen información que puede delatar al emulador. Estas falsas rutas apuntan a un conjunto de archivos con datos que sugieren la presencia de un dispositivo real y que pueden ser descargados desde este enlace.

img_09

  • Localización GPS: el módulo intercepta el método getLastKnowLocation para devolver una latitud y longitud configuradas por el analista.

img_10

  • Propiedades del sistema: muchas de las comprobaciones de estas propiedades se realizan por reflexión. Para impedirlo, se instrumenta el método invoke para detectar cuando se realiza una llamada al método get de android.os.SystemProperties para obtener la propiedad ro.product.name y entonces se devuelve la stringgoogle” en vez de “sdk”.

img_11

Además del punto anterior, la herramienta sobrescribe otro conjunto de propiedades, ocultando aquellas distintivas del emulador y simulando otras que debiesen estar presentes en el teléfono. Podemos ver esas propiedades en la siguiente imagen:

img_12

  • Telefonía móvil: simula datos necesarios para la conexión por la red de datos y llamadas de la operadora móvil, como ser número de línea, SIM, IMEI, código de país, entre otros.

img_13

  • Conexión Wi-Fi: se hookea el método getMacAddress para fingir características de conexión de red inalámbrica.

img_14

Aunque estos módulos resultan muy útiles y funcionan con la mayoría de las muestras, algunas veces nos encontramos con técnicas antiemulación más complicadas o comprobaciones que simplemente no están cubiertas por la herramienta. En tal caso, podemos modificar la aplicación que estamos utilizando o editar el código smali del APK para parchear la funcionalidad antiemulación.

Alterar el código smali

Editar el código smali de la aplicación resulta muy sencillo. Para obtener el código deberemos descompilar el APK utilizando alguna herramienta como apktool. Una vez que hayamos identificado y modificado los archivos necesarios, podremos utilizar esta misma herramienta para reconstruir la aplicación. Alternativamente, puede usarse APKStudio para realizar este proceso mediante una GUI. Finalmente, deberemos firmar el APK con jarsigner.

Para ejemplificar la edición de código smali, tenemos una aplicación muy sencilla que despliega uno u otro texto según si detecta o no que corre en un emulador. La clase de la actividad principal contiene las siguientes líneas de código:

[java]

if (!CheckEmulation.checkEmulator(getApplicationContext())) {
txtLabel.setText(getResources().getString(R.string.device));
}

[/java]

El método checkEmulator es el encargado de realizar una simple comprobación que podemos ver a continuación:

[java]

static boolean checkEmulator(Context context){
TelephonyManager mng = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return mng.getSimOperatorName().equals("Android");
}

[/java]

Si descompilamos la aplicación y navegamos los archivos smali, podremos ver que el anterior método ahora se ve como se ilustra a continuación.

img_15

Al ser ejecutada en el emulador de Android, la aplicación despliega el texto “This is an emulator.”, detectando correctamente al emulador.

img_16

Para evitar esta sencilla comprobación debemos simplemente hacer que checkEmulator retorne siempre false. Para ello, podemos editar el método anterior de modo que quede algo similar a lo que vemos en la próxima imagen:

img_17

Al recompilar, firmar e instalar el APK, podremos ver cómo la función de antiemulación ha sido parcheada.

img_18

Un universo de posibilidades

Los procesos mencionados son algunas de las posibilidades que tenemos al momento de analizar una muestra con este tipo de protección. Por ejemplo, también podríamos elegir utilizar un debugger o bien instrumentar los métodos a través de una herramienta como Frida.

Lo importante es que conozcamos las opciones de las cuales disponemos para poder elegir qué resulta más rápido y sencillo para cada escenario particular al momento de analizar aplicaciones móviles.