jueves, 6 de septiembre de 2012

Creando volcados de memoria en android con LiME

Los que me sigáis en twitter (y los que no también) sabréis (u os enteraréis ahora) que he conseguido recuperar un HTC Google Nexus One que tenía en el cajón del olvido ya que no paraba de reiniciarse. Armado de paciencia conseguí desbloquear el arranque, rootearlo y, utilizando ROM Manager, instalar Cyanogenmod 7.2 tras lo que hasta el momento, y ya van algunos días, no ha vuelto a dar problemas.

La primera prueba que se me ocurrió fué la de utilizar LiME para generar un volcado de memoria del dispositivo y lo que sigue es mi periplo particular incluyendo mis errores (muchos), mis aciertos (muy pocos), enlaces interesantes (algunos) e incluso una petición de soporte al padre de la criatura, Joe Sylve de Digital Forensics Solutions. Pero basta de cháchara y vamos al lio :)

Prerrequisitos

El grueso de la tarea debe realizarse en Linux, pero toda la parte de conexión con el dispositivo utilizando el SDK de Android puede hacerse indistintamente desde Windows o desde Linux. Personalmente todo el proceso previo de "modificación" del smartphone lo hice desde Windows Vista y la comunicación con el dispositivo mediante USB me dió varios quebraderos de cabeza ya que no lo reconocía por falta de controladores adecuados. Para que no os pase lo mismo que a mí indicar que la solución la econtré aquí: [Tutorial] Adb Driver Android 1.0 Install. ¡Bendita la gente que comparte sus conocimientos!

Por probar algo distinto decidí hacerlo esta vez desde Linux, concretamente desde Ubuntu 12.04.1, y para la parte de preparación previa seguí las instrucciones de la página oficial: Initializing a Build Environment.

Por no extenderme mucho primero instalamos java 6 (como root):

$ add-apt-repository "deb http://archive.canonical.com/ lucid partner"
$ apt-get update
$ apt-get install sun-java6-jdk

Instalamos las dependencias (aquí he mezclado las del Android SDK y las necesarias para compilar Cyanogenmod, tal como se indica en el siguiente documento):
$ apt-get install git-core gnupg flex bison gperf build-essential \
zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev \
libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 \
libgl1-mesa-dev g++-multilib mingw32 openjdk-6-jdk tofrodos \
python-markdown libxml2-utils xsltproc zlib1g-dev:i386 \
libsdl1.2-dev libesd0-dev libwxgtk2.6-dev squashfs-tools \
pngcrush schedtool

Y dado que voy a realizar el proceso de conexión siendo root no es necesaria la creación del fichero de reglas udev. Por último no debe olvidársenos habilitar el modo de depuración en el teléfono desde Ajustes, Aplicaciones, Desarrollo, Depuración Android.

Instalando, instalando

Antes de empezar comentar que la mayor parte del proceso está perfectamente descrito en el fichero de documentación incluido con LiME, excepto algunas modificaciones seguro la mayoría debidas a errores tipográficos y la particularidad de mi instalación.

Descargamos e instalamos el Android NDK, concretamente la revisión 8b, la última disponible en el momento de escribir estas líneas:
$ cd /opt
$ wget http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2
$ tar xvjf android-ndk-r8b-linux-x86.tar.bz2
$ ln -s android-ndk-r8b android-ndk
$ rm android-ndk-r8b-linux-x86.tar.bz2

Descargamos e instalamos el Android SDK, concretamente la revisión 20.0.3, la última disponible en el momento de escribir estas líneas:
$ cd /opt
$ wget http://dl.google.com/android/android-sdk_r20.0.3-linux.tgz
$ tar xvzf android-sdk_r20.0.3-linux.tgz
$ mv android-sdk-linux/ android-sdk_r20.0.3
$ ln -s android-sdk_r20.0.3 android-sdk
$ rm android-sdk_r20.0.3-linux.tgz

Para instalar adb y el resto de binarios relacionados arrancaremos el Android SDK manager:
$ cd /opt/android-sdk/tools
$ ./android

y seleccionaremos el paquete correspondiente (Android SDK Platform-tools) desde el entorno gráfico. Me consta que es posible hacerlo también desde la línea de comandos pero ésto último no lo he probado. Si alguien siente la imperiosa necesidad: Is there a way to automate the android sdk installation?

Antes de continuar podemos confirmar la correcta comunicación con el teléfono conectándolo mediante USB y ejecutando:
$ cd /opt/android-sdk/platform-tools
$ ./adb devices
List of devices attached
HT07ZP801363 device

Confirmamos que aparece listado, así que vamos bién.

También descargaremos la última versión de LiME disponible desde el repositorio subversion:
$ cd /opt
$ svn checkout http://lime-forensics.googlecode.com/svn/trunk/ lime

Acertando con el kernel

Para compilar el módulo de LiME y poder cargarlo sin problemas es imprescindible utilizar el código fuente de exactamente la misma versión del kernel instalada en el teléfono. Así que lo primero pasa por determinar la versión que se instala con Cyanogenmod 7.2 lanzando una shell en el dispositivo:
$ cd /opt/android-sdk/platform-tools
$ ./adb shell
# uname -a
Linux localhost 2.6.37.6-cyanogenmod-g0799e00 #1 PREEMPT Sun Nov 13 23:24:39 CET
2011 armv7l GNU/Linux
# exit

Si le echamos un vistazo al documento "Building Kernel from source" desde el wiki de Cyanogenmod obtendremos el enlace para la descarga desde github:

https://github.com/CyanogenMod/cm-kernel

y allí confirmaremos que la rama seleccionada por defecto, y que por lo tanto será la que descargaremos, es android-msm-2.6.37, justo la que necesitamos. Así que descargando que es gerundio:
$ cd /opt
$ git clone git://github.com/CyanogenMod/cm-kernel.git

Compilando, compilando

Para facilitar el proceso de compilación generaremos un fichero con todas las variables a exportar, de forma que podamos ejecutarlo antes de cada sesión:
$ cd /opt
$ vim entorno

export SDK_PATH=/opt/android-sdk
export NDK_PATH=/opt/android-ndk
export KSRC_PATH=/opt/cm-kernel
export CC_PATH=$NDK_PATH/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin
export LIME_SRC=/opt/lime/src

$ source entorno

Descargaremos ahora desde el teléfono el fichero de configuración utilizado para la compilación del kernel y lo ubicaremos adecuadamente:
$ cd $SDK_PATH/platform-tools
$ ./adb pull /proc/config.gz
767 KB/s (12267 bytes in 0.015s)
$ cd /opt
$ gunzip config.gz
$ cp config $KSRC_PATH/.config

y preparamos el kernel para la compilación del módulo de LiME:
$ cd $KSRC_PATH
$ make ARCH=arm CROSS_COMPILE=$CC_PATH/arm-linux-androideabi- modules_prepare

Si todo ha ido bién generaremos ahora un Makefile para el módulo:
$ cd $LIME_SRC
$ mv Makefile Makefile.original
$ vim Makefile

obj-m := lime.o
lime-objs := tcp.o disk.o main.o

KDIR := /opt/cm-kernel

PWD := $(shell pwd)
CCPATH := /opt/android-ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin
default:
# cross-compile for Android emulator
$(MAKE) ARCH=arm CROSS_COMPILE=$(CCPATH)/arm-linux-androideabi- \
-C $(KDIR) M=$(PWD) modules
$(CCPATH)/arm-linux-androideabi-strip --strip-unneeded lime.ko

$(MAKE) tidy

tidy:
rm -f *.o *.mod.c Module.symvers Module.markers modules.order \
\.*.o.cmd \.*.ko.cmd \.*.o.d
rm -rf \.tmp_versions

clean:
$(MAKE) tidy
rm -f *.ko

que lanzaremos a continuación:
$ make

Ya lo tenemos, asi que a probarlo volcando la memoria en un fichero (ram.lime) dentro de la sdcard:
$ cp lime.ko $SDK_PATH/platform-tools
$ cd $SDK_PATH/platform-tools
$ ./adb push lime.ko /mnt/sdcard/lime.ko
133 KB/s (7736 bytes in 0.056s)
./adb shell
# insmod /sdcard/lime.ko "path=/sdcard/ram.lime format=lime"
insmod: init_module '/sdcard/lime.ko' failed (Exec format error)

Y empiezan los errores. El módulo se resiste a cargarse así que veamos si el log del sistema nos dá mas datos:
# dmesg | grep lime
<3>[19677.981170] lime: version magic '2.6.37.6-cyanogenmod-g2a32a61-dirty
preempt mod_unload ARMv7 ' should be '2.6.37.6-cyanogenmod-g0799e00 preempt
mod_unload ARMv7 '
# exit

¿Cual es el problema?

Tal como se indica en la sección "2.8. Building modules for a precompiled kernel" dentro del documento "The Linux Kernel Module Programming Guide", cuando compilamos un módulo se agrega automáticamente una cadena estática, vermagic, que indentifica la versión concreta del kernel para la que está compilado. Concretamente para nuestro módulo obtendríamos:
$ cd $LIME_SRC
$ modinfo lime.ko
filename: lime.ko
license: GPL
depends:
vermagic: 2.6.37.6-cyanogenmod-g2a32a61-dirty preempt mod_unload ARMv7
parm: path:charp
parm: dio:bool
parm: format:charp

y he ahí el fallo, las cadenas no coinciden y el kernel se niega a cargar el módulo. Probando cosas detecto que la opción de modificar la variable EXTRAVERSION en el Makefile del kernel no funciona con Android, al menos no directamente. Para solucionarlo, y dado que disponemos de la versión adecuada de las fuentes del kernel, primero tendremos que modificar el script setlocalversion el cual se encarga de obtener el número de revisión desde el repositorio git:
$ cd $KSRC_PATH
$ vim scripts/setlocalversion

... 27 if test $# -gt 0 -o ! -d "$srctree"; then
28 usage
29 fi
30
31 exit
32
33 scm_version()
...

y ahora sí, modificar la variable EXTRAVERSION dentro del Makefile de generación del kernel para obtener la cadena deseada:
$ vim Makefile

1 VERSION = 2
2 PATCHLEVEL = 6
3 SUBLEVEL = 37
4 EXTRAVERSION = .6-cyanogenmod-g0799e00
5 NAME = Flesh-Eating Bats with Fangs
...

Si repetimos ahora el proceso de compilación:
$ make clean
$ make ARCH=arm CROSS_COMPILE=$CC_PATH/arm-linux-androideabi- modules_prepare
$ cd $LIME_SRC
$ make clean
$ make
$ modinfo lime.ko
filename: lime.ko
license: GPL
depends:
vermagic: 2.6.37.6-cyanogenmod-g0799e00 preempt mod_unload ARMv7
parm: path:charp
parm: dio:bool
parm: format:charp

confirmaremos que ya tenemos la cadena buscada, así que ahora utilizaremos LiME en el dispositivo:
$ cp lime.ko $SDK_PATH/platform-tools
$ cd $SDK_PATH/platform-tools
$ ./adb push lime.ko /mnt/sdcard/lime.ko
145 KB/s (7732 bytes in 0.051s)
$ ./adb shell
# insmod /sdcard/lime.ko "path=/sdcard/ram.lime format=lime"
insmod: init_module '/sdcard/lime.ko' failed (No such file or directory)

¿que co**nes pasa ahora?
# dmesg | grep lime
<4>[20493.266754] lime: Unknown symbol _GLOBAL_OFFSET_TABLE_ (err 0)

Una busqueda en Google nos devuelve la solución, que pasa por añadir "EXTRA_CFLAGS=-fno-pic" en los comandos de compilación, y que se menciona en cualquiera de los siguientes enlaces:

NDK Toolchain and "Unknown symbol _GLOBAL_OFFSET_TABLE_" in kernel module
Acquiring volatile memory from Android based devices with LiME Forensics, Part I

Volvemos a compilar con la opción extra, empenzando por el kernel:
$ cd $KSRC_PATH
$ make clean
$ make ARCH=arm CROSS_COMPILE=$CC_PATH/arm-linux-androideabi- \
EXTRA_CFLAGS=-fno-pic modules_prepare

para a continuación modificar el Makefile de compilación de LiME para obtener el módulo necesario:
$ cd $LIME_SRC
$ make clean
$ vim makefile

9 # cross-compile for Android emulator
10 $(MAKE) ARCH=arm CROSS_COMPILE=$(CCPATH)/arm-linux-androideabi- \
EXTRA_CFLAGS=-fno-pic -C $(KDIR) M=$(PWD) modules

$ make
$ cp lime.ko $SDK_PATH/platform-tools

NOTA: para capturar los mensajes dirigidos por el módulo al log del sistema de forma sencilla es recomendable activar la opción de debug para lo que simplemente deberemos descomentar la siguiente línea:
$ vim $LIME_SRC/lime.h

...
54 //#define LIME_DEBUG
...

Una vez compilado el módulo y cargado en memoria bastará con hacer un grep del comando dmesg utilizando la cadena "LiME".

Volcando, volcando

El comando que estábamos utilizando hasta el momento para insertar el módulo de lime obtendría el fichero de volcado en la raíz de la tarjeta de memoria del dispositivo, por lo que para asegurar el orden de volatilidad no es lo más recomendable, al menos no sin duplicar previamente dicha tarjeta.

Si a lo anterior le unimos que en las pruebas con mi teléfono el proceso va muuuuy lento provocando además un error con tan sólo aproximádamente 237 MB volcados de los 424 MB disponibles y dejando los siguientes registros de salida:
# dmesg | grep LiME
dmesg | grep LiME
<4>[ 334.001678] [LiME] Parameters
<4>[ 334.002136] [LiME] PATH: /sdcard/ram.lime
<4>[ 334.003051] [LiME] DIO: 1
<4>[ 334.003479] [LiME] FORMAT: lime
<4>[ 334.003906] [LiME] Initilizing Dump...
<4>[ 5323.732757] [LiME] Direct IO may not be supported on this file system. Retrying.
<4>[ 5323.733398] [LiME] Direct IO Disabled

se entenderá porque recomiendo el volcado sobre la red. Comentar que el problema está reportado pero dado que el creador de la herramienta no tiene ningún HTC Google Nexus One para reproducirlo y con mis conocimientos no se me ocurren alternativas para obtener más datos de depuración el tema está un poco estancado. Si se os ocurre algo decidlo, please.

Para lanzar el volcado a través de la red primero subimos el módulo y después asociamos un puerto TCP local a un puerto TCP en el dispositivo a través del USB:
$ cd $SDK_PATH/platform-tools
$ ./adb push lime.ko /mnt/sdcard/lime.ko
138 KB/s (6676 bytes in 0.047s)
$ ./adb forward tcp:4444 tcp:4444

Ahora sólo restará cargar el modulo en memoria con los parámetros adecuados:
$ ./adb shell
# insmod /sdcard/lime.ko "path=tcp:4444 format=lime"

y en otra consola de nuestro sistema linux recoger el fichero resultante mediante netcat:
$ nc localhost 4444 > ram.lime

Lo ideal ahora sería continuar indicando cómo analizar el resultado utilizando volatility ... y en ello estoy, a ver si lo consigo y redondeamos.

6 comentarios:

SPaNKeR dijo...

Muy buen post. Es un infierno todos los impedimientos que hay que saltar hasta conseguir cargar el cochino módulo ;D

neofito dijo...

Cierto, pero lo mejor es que al final funciona, y con el soporte de esta arquitectura bajo volatility la ventana de posibilidades que se abre es realmente impresionante.

Saludos, nano! ;-)

SPaNKeR dijo...

Por cierto, conseguiste crear un profile de android para volatility? He visto en la lista de correo que lo estuviste viendo con Andrew Case. No parece que haya mucha documentación por ahí sobre como hacerlo.

Gracias!

neofito dijo...

Lo cierto es que como dices intercambie varios correos, pero viendo que el soporte para arm estaba en proyecto y andaban un poco liados con el omwf2012 decidí no incordiar mas y ver como evoluciobaba el tema.

Por mi parte conseguí modificar uno de los fuentes y crear un makefile que compilaba y obtenía un .dwarf, pero dadas mis limitaciones achaco el problema mas a mis modificaciones que a un fallo de la herramienta. Pero seguiremos intentándolo :-)

Saludos

Rocio dijo...

Esta bueno disfrutar de aprender cosas relacionadas con la informática y por eso trato de conocer muchas cosas gracias a la web. Con la memoria sd suelo almacenar mucho tipo de cosas variadas

MARIA ELENA dijo...

DISCULPA TENGO UN SONY XPERIA MIROS T23I Y SE MME APAGA CUANDO ME QUIERO METER A UNA APLICACION Y APARECE SISTEMA ANDROID QUE PUEDO HACER DAME UNA OPINION PORFABOR