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.
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.
Dentro de la funcionalidad que encontramos parcheada tenemos la siguiente:
- Monkey: se hookea el método
isUserAMonkey
retornando siemprefalse
, de modo que la muestra no pueda saber si se está utilizandoadb shell monkey
para detonar comportamientos.
- Datos del build: cada vez que se llama el método
onCreate
de la claseandroid.app.Application
la aplicación devuelve a cualquier proceso no conocido información personalizada del build del sistema.
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”.
- TaintDroid: Oculta funcionalidad específica de TaintDroid al encubrir la clase
dalvik.system.Taint
.
- 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
dejava.io.File
siempre que la ruta pasada por parámetro esté almacenada en el array de rutas predefinidas por el analista.
- 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
.
- IOBinder: a través de un hook al método
open
delibcore.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.
- Localización GPS: el módulo intercepta el método
getLastKnowLocation
para devolver una latitud y longitud configuradas por el analista.
- 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étodoget
deandroid.os.SystemProperties
para obtener la propiedadro.product.name
y entonces se devuelve la string “google” en vez de “sdk”.
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:
- 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.
- Conexión Wi-Fi: se hookea el método
getMacAddress
para fingir características de conexión de red inalámbrica.
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.
Al ser ejecutada en el emulador de Android, la aplicación despliega el texto “This is an emulator.”, detectando correctamente al emulador.
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:
Al recompilar, firmar e instalar el APK, podremos ver cómo la función de antiemulación ha sido parcheada.
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.