LiME on Android AVDs for Volatility Analysis

Gabrio Tognozzi
5 min readJul 12, 2019

--

This story is about using LiME on Android AVDs to Dump RAM images and analyzing them with Volatility.

After the previous post about being able to Use a Custom Kernel with Android AVDs, I’ve started investigating how to do some basic forensic analysis with Volatility on a running AVD. I came across a module called LiME that was shown to be usefull to dump RAM images for forensic analysis with Volatility. So, now I will walk through my experience of:

  1. Modifying the AVD’s Linux Kernel to be able to dynamically load Modules

2. Cross-compiling the LiME module for the Linux Kernel used by a running instance of the AVD.

3. Creating a Profile to be used by Volatility to analyze the RAM image dumped from the device.

1. Modifying AVD’s Linux Kernel to enable Insmod

By default the Goldfish Linux Kernel, that is the kernel that is used for the virtualized devices, doesn’t ships with the kernel option needed to enable insmod (the shell command that lets us dynamically load a module into the kernel). In order to enable the Dynamic Loading of Kernel modules we have to modify the step 3 of my previous story about using a custom Linux Kernel for Android AVDs in such a way that the ‘CONFIG_MODULES=y’ option will be used when building the kernel. The new step 3 follows:

# We first build a template .config file
make ARCH=x86_64 x86_64_ranchu_defconfig
# Here we modify .config to contain CONFIG_MODULES=y
vi .config
# Then we build the kernel as in the previous story
make -j16 ARCH=x86_64 CROSS_COMPILE=x86_64-linux-android-

If all works, when the kernel is built the ‘CONFIG_MODULES=y’ line will still exists in the .config file. I was having troubles making the change survive after the KBuild system runs because I was modifying the .config file in the wrong way. I found out that the proper way to enable CONFIG_MODULES is to override the line ‘#CONFIG_MODULES is not set’ with the new config line otherwise bad things will happen.

2. Cross Compiling LiME Module for our Linux Kernel

We will now have a working Linux Kernel for our AVD with dynamic loading of modules enabled. Now is the moment to Cross Compile the LiME module for our Android Device, in that way we will be able to dump ram images of such device and proceed with our investigations.

In order to let the KBuild system compile our module for the precise version of the Linux Kernel used by the AVD (we need this step, otherwise the module will not load ) we have to compose a Makefile with a few variables that we will use to make things work.

We will define the KDIR_GOLD variable as the path to our Goldfish Kernel source code, and CCPATH as the path to the compiler to be used. My Makefile will be as follows:

# This is a sample Makefile for cross-compiling the LiME LKMobj-m := lime.o
lime-objs := tcp.o disk.o main.o
KDIR_GOLD := /home/bp/Public/goldfishPWD := $(shell pwd)
CCPATH := /home/bp/Public/x86_64-linux-android-4.9/bin
default:
# cross-compile for Android emulator
$(MAKE) ARCH=x86_64 CROSS_COMPILE=$(CCPATH)/x86_64-linux-android- -C $(KDIR_GOLD) M=”$(PWD)” modules
$(CCPATH)/x86_64-linux-android-strip — strip-unneeded lime.ko
mv lime.ko lime-goldfish.ko
$(MAKE) tidytidy:
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

We have almost done! at this point, I got an annoying issue. While building the LiME module I got some ‘undefined’ warnings, about some functions, that I was happy to ignore. But it always comes with a cost. When later pushing the module to the AVD and trying to insmod it, I was experiencing a ‘file not found’ error for a file that was right in front of me. It couldn’t be true. After further investigating I found out, reading ‘dmesg’ output, that the undefined references were still causing troubles.

Fortunately the warnings were about some troubles on three functions that were ldigest_{final,init,update}. After some grepping I found out that they were only needed for using RAM hashes (digests) for integrity checks. I didn’t needed this feature so I worked around this problem wiping out all the code related to that functions. LOL. I know I will pay later for this. The git diff about the main.c follows:

diff — git a/src/main.c b/src/main.c
index a442c56..02244d3 100644
— — a/src/main.c
+++ b/src/main.c
@@ -42,9 +42,6 @@ extern int write_vaddr_disk(void *, size_t);
extern int setup_disk(void);
extern void cleanup_disk(void);

-extern int ldigest_init(void);
-extern int ldigest_update(void *, size_t);
-extern int ldigest_final(void);

static char * format = 0;
static int mode = 0;
@@ -133,8 +130,6 @@ static int init() {
return err;
}

- if(compute_digest == LIME_DIGEST_COMPUTE)
- compute_digest = ldigest_init();

for (p = iomem_resource.child; p ; p = p->sibling) {

@@ -158,9 +153,6 @@ static int init() {

cleanup();

- if(compute_digest == LIME_DIGEST_COMPUTE)
- compute_digest = ldigest_final();
-
return err;
}

@@ -271,8 +263,6 @@ static void write_range(struct resource * res) {
}

ssize_t write_vaddr(void * v, size_t is) {
- if(compute_digest == LIME_DIGEST_COMPUTE)
- compute_digest = ldigest_update(v, is);

return RETRY_IF_INTURRUPTED(
(method == LIME_METHOD_TCP) ? write_vaddr_tcp(v, is) : write_vaddr_disk(v, is)
(END)

After that modification I built the kernel module and pushed it to the AVD. then I followed the instruction on the official LiME Github repository and I got my RAM snapshot!

3. Creating a Volatility Profile, and Doing some basic Volatility Analysis

I didn’t resist to complete my work and check if all worked correctly. I’ve downloaded volatility from the official Volatility Github Repository and installed dwarfdump with apt on my host system, because we will need it in a second.

To get our forensic analysis tool to work we have to build a profile for our considered linux kernel, for this we need the System.map file, that is in the root folder of the Goldfish Kernel, and a module.dwarf file that we can build using dwarfdump.

Volatility, inside the path volatility/tools/linux offers a template Makefile that will use dwarfdump to create our module.dwarfdump file. I’ve followed the Volatility Doc for Android, modified the Makefile as follows, and get the needed file:

# Makefile to build module.dwarf fileobj-m += module.o
KDIR := ~/Public/goldfish
CCPATH := ~/Public/x86_64-linux-android-4.9/bin
DWARFDUMP := dwarfdump
-include version.mkall: dwarfdwarf: module.c
$(MAKE) ARCH=x86_64 CROSS_COMPILE=$(CCPATH)/x86_64-linux-android- -C $(KDIR) CONFIG_DEBUG_INFO=y M=$(PWD) modules
$(DWARFDUMP) -di module.ko > module.dwarf
clean:
rm -f module.dwarf

After this step we have both the System.map and module.dwarf files. now we can build the zip, put it inside the volatility profile folder and check if everything works!

zip /volatility/plugins/overlays/linux/Golfish.zip module.dwarf System.mappython vol.py — profile=LinuxGolfish-3_10_n-x86 -f ~/ram.dump linux_pslist

It works!

Conclusions

It is never easy when we have to deal with Linux Kernel, Modules, etc. but we never give up! If you have comments, suggestions, or you do have some knowledge about DWARF format to share, feel free to comment below!

--

--