Android Process Memory Dumps with Memdump – Android 4.4+ (on Ubuntu 16.04)
Memdump: [a little more straightforward than Memfetch … in my opinion]
Basically the idea is to get the code and cross-compile it using the Android NDK (Native Develpment Toolkit) toolset on Ubuntu, then getting the binary and transferring it onto your device and running it with the right permissions.
Update [2017-01-16]: I’m not sure whether this will work for Android on both x86 and ARM architectures. I tested it on an ARM architecture (physical device), and it worked. I’m yet to test it on an x86 architecture. Will update after testing. (My feeling is that it should). I forgot that there are multiple folders in the /libs
directory that are created. One for each of the architectures. Pick the right executable from the right folder for your architecture, and it should work.
Update [2017-01-18]: I tested this entire thing on an Android 7.1.1 (Nougat) emulator, and eventually got it working. It seems that from Android 5.0 you will probably get an error like “error: only position independent executables (PIE) are supported“. From what i’ve read here this is is due to a security feature implemented from Android 5.0 onwards. The Android.mk
file has to be modified a bit (i’ve added the modifications needed) to enable PIE for any executables from Android 5.0 onwards. (Truth is it seems the PIE feature is available from 4.1, but it is disabled, and from 5.0 it is enabled by default)
Getting the code and setting it up:
Find the code here – http://security.stackexchange.com/questions/62300/memory-dumping-android (hoping that the link is still alive, it’s among the answers by Tal Aloni)
Create a directory in an appropriate location of your choice. I created one called memdump
on my Desktop. Then create a directory with the name jni
in that directory (this is important for using ndk-build
later).
cd ~/Desktop mkdir memdump cd memdump mkdir jni cd jni
Create a file in the jni
directory and copy-paste the code from the link provided above into the file. Name the file memdump.c. I’ve put the code here below also, just for completeness:
#include <stdio.h> #include <stdlib.h> #include <limits.h> #include <sys/ptrace.h> #include <sys/socket.h> #include <arpa/inet.h> void dump_memory_region(FILE* pMemFile, unsigned long start_address, long length, int serverSocket) { unsigned long address; int pageLength = 4096; unsigned char page[pageLength]; fseeko(pMemFile, start_address, SEEK_SET); for (address=start_address; address < start_address + length; address += pageLength) { fread(page, 1, pageLength, pMemFile); if (serverSocket == -1) { // write to stdout fwrite(page, 1, pageLength, stdout); } else { send(serverSocket, &page, pageLength, 0); } } } int main(int argc, char **argv) { if (argc == 2 || argc == 4) { int pid = atoi(argv[1]); long ptraceResult = ptrace(PTRACE_ATTACH, pid, NULL, NULL); if (ptraceResult < 0) { printf("Unable to attach to the pid specified\n"); return; } wait(NULL); char mapsFilename[1024]; sprintf(mapsFilename, "/proc/%s/maps", argv[1]); FILE* pMapsFile = fopen(mapsFilename, "r"); char memFilename[1024]; sprintf(memFilename, "/proc/%s/mem", argv[1]); FILE* pMemFile = fopen(memFilename, "r"); int serverSocket = -1; if (argc == 4) { unsigned int port; int count = sscanf(argv[3], "%d", &port); if (count == 0) { printf("Invalid port specified\n"); return; } serverSocket = socket(AF_INET, SOCK_STREAM, 0); if (serverSocket == -1) { printf("Could not create socket\n"); return; } struct sockaddr_in serverSocketAddress; serverSocketAddress.sin_addr.s_addr = inet_addr(argv[2]); serverSocketAddress.sin_family = AF_INET; serverSocketAddress.sin_port = htons(port); if (connect(serverSocket, (struct sockaddr *) &serverSocketAddress, sizeof(serverSocketAddress)) < 0) { printf("Could not connect to server\n"); return; } } char line[256]; while (fgets(line, 256, pMapsFile) != NULL) { unsigned long start_address; unsigned long end_address; sscanf(line, "%08lx-%08lx\n", &start_address, &end_address); dump_memory_region(pMemFile, start_address, end_address - start_address, serverSocket); } fclose(pMapsFile); fclose(pMemFile); if (serverSocket != -1) { close(serverSocket); } ptrace(PTRACE_CONT, pid, NULL, NULL); ptrace(PTRACE_DETACH, pid, NULL, NULL); } else { printf("%s <pid>\n", argv[0]); printf("%s <pid> <ip-address> <port>\n", argv[0]); exit(0); }
Now create another file in the same jni
directory and name the file Android.mk
The instructions in the Android.mk
file should look like the following:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # [Update 2017-01-18]: These 4 lines below, including the comments. # Enable PIE manually. Will get reset on $(CLEAR_VARS). This # is what enabling PIE translates to behind the scenes. LOCAL_CFLAGS += -fPIE LOCAL_LDFLAGS += -fPIE -pie LOCAL_MODULE := memdump LOCAL_SRC_FILES := memdump.c include $(BUILD_EXECUTABLE)
Setting up Android Build Environment:
I used Android Studio (version 2.2.3) to get to the Android SDK Manager GUI and install the NDK from there. You can install Android Studio in Ubuntu using umake
. Install umake
as follows:
sudo apt-get install umake
The install Android Studio:
umake install android
Run Android Studio and find the Android SDK Settings ( > > >). Under the SDK Tools
tab click the CMake
, LLDB
and NDK
checkboxes.
Click Apply or OK. A dialog should appear where you accept the license conditions and then the requisite tools should begin installing.
(For our case here, we will use only ndk-build
since it was what worked. Ideally, you could use CMake
… and actually the latest Android documentation suggests using CMake
henceforth since i think they plan to retire / deprecate ndk-build
eventually … All the same, i think the Android.mk
file I found on StackExchange was written for ndk-build
so that’s what we’ll use. Also i’m not yet sure how to use CMake
for this task. If i figure it out i’ll write another blog post.) Also you could use Android Studio directly for this entire task of building/compiling the C code to get an Android/ ARM executable, but i don’t know how to configure it correctly yet.
Once you have the NDK installed, navigate to the ~/Desktop/memdump
directory and while there execute ndk-build
, which you can find under /home/Android/Sdk/ndk-bundle/
cd ~/Desktop/memdump /home/Android/Sdk/ndk-bundle/ndk-build
If you happen to be on a Windows machine, you can get ndk_build.cmd
to do the job for you. Navigate to the folder where you have memdump
and you can run:
e.g:
C:\Users\user1\Desktop\memdump> C:\Users\user1\AppData\Local\Android\sdk\ndk-bundle\ndk-build.cmd
At this point the code should build and compile creating a /libs
directory an an /obj
directory. Navigate into the libs
directory and you will see directories for various architectures. Under each directory there is an executable for that specific architecture. We’re mainly concerned at this moment with the one under armeabi
Installing the Memdump executable on an Android device:
In order to use the Memdump executable, we need to get it onto an Android device in a place that allows execution, give the executable execute permissions and run it.
NB: We assume that the Android device is rooted properly and that the specific Superuser management app allows root access from the adb shell. (I haven’t tested it on an unrooted device, but i still suspect that the device needs to be rooted first)
Navigate to the directory containing the adb
executable. Get into the adb shell and navigate to the /data/local/tmp
(since execution of binaries is allowed there). We want to put the memdump
executable in a directory in here. Create a directory here called mem_dump_tools
(or whatever you’d like to call it). This is where we will put the memdump
executable
cd ~/Android/Sdk/platform-tools ./adb devices -l ./adb shell su root cd /data/local/tmp mkdir mem_dump_tools
Now push the memdump executable from the Ubuntu machine into the Android devices:
./adb push ~/Desktop/memdump/libs/armeabi/memdump /data/local/tmp/mem_dump_tools
Navigate into the mem_dump_tools directory on the Android device and give the memdump executable permissions to execute:
./adb shell cd /data/local/mem_dump_tools sudo chmod 755 memdump
(or you can use sudo chmod+x memdump
)
Verify that it has got the executable permisions by running ls -al
to list the files with their properties.
Executing the memdump tool:
The memdump script has two execution formats. One to dump to a directory and the other to dump over a network network port
memdump <pid> > /Path/to/Directory/to/dump/to memdump <pid> <ipaddress> <port>
NB: Make sure you don’t forget the “>” to direct the output of stdout to a file (or elsewhere)
Hack: (For those interested in Forensics & Reversing). If you get the Position Independent Executables (PIE) error here because you missed the lines LOCAL_CFLAGS += -fPIE
and LOCAL_LDFLAGS += -fPIE -pie
in the Android.mk
file, there is an interesting hack (credit to Koorosh Ghorbani ) that i found on Stackoverflow. You can open the executable with your favourite Hex Editor and you just have to change the 17th byte from 02
to 03
and the executable should now work without the PIE error.
We want to dump the process memory of a an application E.g. Chrome, Facebook, Whatsapp …etc. into a directory on the SDCard. Let’s use Chrome for now
Let’s first create a directory where the dumps should go.
./adb shell su root cd /storage/extSdcard mkdir MEM_DUMPS
Now let’s get the process id
of the process that we want to target
ps | grep chrome
Pick the pid
from this. You should get 3 processes (one with sandbox
, another with privileged
affixed and another just plain com.android.chrome
… pick this last one with nothing affixed to the name)
Then run memdump as follows:
./memdump <pid> > /storage/extSdcard/MEM_DUMPS/<mem_dump_file_name>
E.g.: ./memdump 1234 > /storage/extSdcard/MEM_DUMPS/chrome.dmp
The dumping process should now begin (there’s no real progress report, just the cursor blinking, or hanging), but it should take some seconds to minutes depending on your phone’s processing capabilities (for Chrome i got an 800MB dump file so give it some time and it tool like 2min, or try some less memory intensive app that might result in a smaller process memory dump file)
Sources:
http://corochann.com/build-executable-file-with-android-ndk-after-lollipop-android-api-21-388.html
http://stackoverflow.com/questions/30498776/position-independent-executables-and-android-lollipop
Android Process Memory Dumps with memfetch – Android 4.4.2 (on Ubuntu 16.04)
I used 2 different C code scripts to achieve the same goal of achieving the process memory dump. The specific code scripts are referred to as Memfetch (by Michal Zalewski – found on his blog) and Memdump (by Tal Aloni – found on StackExchange)
Update [2017-01-16]: I’m not sure whether this will work for Android on both x86 and ARM architectures. I tested it on an ARM architecture (physical device), and it worked. I’m yet to test it on an x86 architecture. Will update after testing.
Memfetch:
Find the code from the author’s webpage here – http://lcamtuf.coredump.cx/soft/memfetch.tgz
Unzip/Extract the code from the TarGZ archive
tar -xvf memfetch.tgz
Get into the directory:
cd memfetch
Use the ls
command to list the files. The files should be listed as below:
COPYING Makefile memfetch.c mffind.pl README
Now install the gcc compiler for Android on ARM (not sure if this is what it’s described as):
sudo apt-get install gcc-arm-linux-android-eabi
(some instructions say use the gcc-arm-linux-gnueabi
but this didn’t work for me )
Edit the Makefile
Normally at this point you should be able to run the make
command and compiling should work, however in Ubuntu the Canonical developers seem to have moved some key .h
source files around causing problems. The first file that might cause problems if you run the make
command will probably be this is because Ubuntu has moved them from the original location of
/usr/include/asm
to be in the kernel source files /usr/src/linux-headers-[your-specific-kernel]/include/asm-generic
Make sure you’ve installed build-essential
for this path to be existent
sudo apt-get install build-essential
You can get to the correct path with:
cd /usr/src/linux-headers-$(uname -r)/include/asm-generic
Once you locate the asm-generic
folder check that the page.h
file is present.
Now the best way to solve this problem is to create a symbolic link (symlink) in /usr/include/
called asm
that links to /usr/src/linux-headers-[your-specific-kernel]/include/asm-generic/
. This is done with the following command:
sudo ln -s /usr/src/linux-headers-$(uname -r)/include/asm-generic /usr/include/asm
Even with this, there will still be some problems because there are some .h
files in asm-generic
that will be looking for asm-generic
in /usr/include/
where the folder doesn’t actually have those header files. So an extra include (-I
) directive will need to be added in the Makefile
The beginning of your make file should look like this:
FILE = memfetch CFLAGS = -Wall -O9 -static CC = arm-linux-androideabi-gcc
NB: its a capital ‘O’ not a zero, and it’s a 9 (nine), not a ‘g’. The “O” “9” directive is some optimization thing (i don’t know if it’s necessary or not)
Run make
at this point. If it works, then great, you should get a memfetch
executable file in your memfetch
directory if not, follow on.
If you run make
and you still get errors of missing .h
files, what i did was to just copy the files from /usr/src/linux-headers-$(uname -r)/include/asm-generic
to /usr/include/
e.g:
sudo cp /usr/src/linux-headers-$(uname -r)/include/asm-generic/memory_model.h /usr/include/asm-generic/memory_model.h
The following files were missing …
getorder.h
/linux/compiler.h
/linux/log2.h
/linux/bitops.h
/linux/irqflags.h
/linux/typecheck.h
At this point i got more files in /bitops that were missing, so i decided to copy the entire directory :
cd /usr/include/asm-generic
sudo mkdir bitops
sudo cp /usr/src/linux-headers-$(uname -r)/include/asm-generic/bitops/* /usr/include/asm-generic/bitops/
At this point i finally ran the make
command in the the memfetch
directory and an executable was created. There were a couple of warnings, but no errors and the executable worked when I pushed into onto the Android device.
Pushing to the Android Device and Executing “Memfetch”:
NB: We are assuming that the device is properly rooted, and the setting for giving adb shell
root permissions has been set in your “Super User” management app.
Go to the adb
executable location, which might be /home/Android/Sdk/platform-tools
it could also be elsewhere … depending on where you installed it
cd /home/Android/Sdk/platform-tools
The best location to push the executable is /data/local/tmp
. Let’s create a directory in this location and use the adb push
command to push the executable here
./adb shell su root cd /data/local/tmp mkdir mem_dump_tools exit exit
We exited first all the way out so that we can run the ./adb push
command
./adb push ~/Desktop/memfetch/memfetch /data/local/tmp/mem_dump_tools/
Verify that the memfetch
executable has been pushed to the right location:
./adb shell su root cd /data/local/tmp/mem_dump_tools ls -al
The memfetch
executable should be in place however it cannot be executed because it does not have execute permissions. We can give it execute permissions with the following command (assuming we are still the root
user)
chmod 755 memfetch
(As a side note: chmod u+x memfetch
should also work.)
Verify that the Execute permissions have been applied
ls -al
You should see rwx
against the name of the memfetch executable. (The x
being the important thing)
Now if we run a particular app and search this process’ ID we can dump the process memory. Pick an app e.g. Google Chrome and fire it. Browse to some page
On the adb shell:
ps | grep chrome
You should get 1-3 processes with Chrome (one with sandboxed
and another with privileged
attached to the process name). Pick the process ID of the process that is plain com.android.chrome
Now we can run memfetch
./memfetch
e.g: ./memfetch 2314
if the process id is “2314”
You should now get some output to screen showing that the memory-mapped regions are being copied. The result is that for each address range (block) from the /proc//mem
folder there is a sub folder called map
that contains the mappings. These mappings result in an individual “region dump” per file (with a .bin
extension) and each region dump filename is appended into a single file with a /lst
extension containing all the filenames of all the regions dumped. So the end result is a lot of .bin
files and a single .lst
file.
NB: If at this point when you try to run memfetch
and all you get is a listing of the available options/directives, and nothing else, then you need to comment out some section of the code in memfetch.c
and recompile. I don’t know why this is the case, but someone on StackExchange [2] figured this out and it also worked for me.
The lines to comment out are:
while ((opt=getopt(argc,(void*)argv, "+samwS:h"))!=EOF) switch(opt) case 's': waitsig=1; break; case 'a': skipmap=1; break; case 'w': textout=1; break; case 'm': avoid_mmap=1; break; case 'S': if (sscanf(optarg,"%x",&onlyseg)!=1) fatal("Incorrect -S syntax (hex address expected).\n"); break; default: usage(argv[0]); }
With that, everything should work.
This blog post has become too long, so i’ll do memdump
in the next one …
Sources:
[1]. http://lcamtuf.coredump.cx/memfetch.tgz
[2]. http://stackoverflow.com/questions/18372120/memfetch-with-android-samsung-galaxy-nexus
Android Process Memory Dumps – Notes
Disclaimer: I don’t really understand everything about the workings of RAM memory and the OS. These are just my notes on how i got RAM Process Memory Dumps of Android Apps.
Intro:
Capturing the process memory from a specific running process (application) in Android seems to have been more difficult that I thought. That’s probably because of the way Android is built that processes run under their own individual users and their respecting permissions.
Reading directly from /proc/<pid>/mem
also seems to have been hindered since a process cannot read another process’ memory in Android (i think in some other Unix/Linux distributions at least reading seems to be possible)
A lot of sources talk about capturing “heap” dumps, but i wanted the entire process memory including the stack, the instructions (and essentially anything else). Heap dumps can be acquired through the DDMS tool in Android Studio (and somehow similarly in Eclipse also). The basic idea is that Android Studio provides RAM profiling tools for analyzing app runtime behaviour.
You can take heap dump from DDMS. According to most sources, it seems it needs to be converted from the default HPROF format to something that can be analyzed by the Java MAT tool (i’m not sure but i think DDMS now does all this automatically for you).
What I wanted was a full memory dump of the process and I couldn’t seem to find a way except through using the memfetch tool (by Michal Zalewski) compiled for Android or some smartly written script called memdump (by Tal Aloni) found on StackExchange.
Both scripts are written in C, so I had to compile them for Android and get them running on a phone in order to achieve my goal … and how this was done is the subject of the next post.
Major Sources:
[1]. Sylve, J., Case, A., Marziale, L., Richard, G.G.: Acquisition and analysis of volatile memory from android devices. Digital Investigation. 8, 175–184 (2012). here or here
[2]. http://security.stackexchange.com/questions/62300/memory-dumping-android
[3]. http://lcamtuf.coredump.cx (look for the memfetch code here)
Android FileSystem – Notes
App Locations:
/system/apps
– Pre-installed bloatware apps/system/priv-apps
– Privileged apps (mounted read-only to prevent changes)/data/app
– Normal apps in internal memory/mnt/sdcard/.android_secure
– Apps stored on external memory go into an encrypted container/mnt/asec
– These apps need to be decrypted to run, so during runtime they are found as a decrypted copy on atmpfs
here- This
.android_secure
container cannot be opened directly from the Android device, however if you plug the SD Card into another computer through a card reader, the.apk
files now have the extension.asec
connected to the same files on/mnt/asec
- Nxt
App Data:
/data/data/<package_name>
– Default location for application data on internal storage./mnt/sdcard/Android/data/<package_name>
– Default location for application data on external storage (if the developer sticks to the rules outlined on the Android Developer Documentation here)
Binary Executable Test Locations:
/data/local/tmp
– Location where you can put executables (NDK compiled / Linux ARM built)
Accessing the SDCard on the Emulator:
First make sure you’ve indicated that you want an SD Card for your Android Virtual Device in the AVD Manager while creating
- You can find the path of your sd card with
cat /proc/mounts
anddf -h
- It should be at
/mnt/media_rw/<8-Character-Serial-Number>
- e.g.
/mnt/media_rw/1CEF-2AB1
- e.g.
Sources:
[1]. http://android.stackexchange.com/questions/3002/where-in-the-file-system-are-applications-installed
Step by step Guide to using LiME – The Linux Memory Extractor
I’m no expert on dumping RAM memory from Linux machines, i’m just trying to explain the steps that i used to get it working – because it was not as intuitive for a n00b like me )
Note: The best way (and possibly the most forensically sound way) is to have the LiME source compiled (?) earlier on another Linux machine, then you transfer the resulting files (in this case a “.ko” file ) onto a USB drive that you will use to plug into the “suspect” Linux machine and dump the memory onto the USB disk (Make sure you have a large enough USB disk to dump the memory).
- Download the LiME source code from the Google Code repository ( https://code.google.com/p/lime-forensics/ )
- Compile it using the Linux “make” command. It looked something like this for me:
user1@UbuntuMachine: /media/USBDriveName/lime-forensics-1.1-r17/src$ make
- The result was that it created a “.ko” file in the current directory:
lime-3.2.0-59-generic.ko
- Now move the USB to the suspect machine. In this case an Ubuntu 32-bit machine. Plug the USB extraction drive into the machine (assuming that it mounts successfully, otherwise you have to mount it yourself. This isn’t very forensically sound, but there’s not much choice here).
- Run the command:
suspect@UbuntuSuspectMachine: /media/USBDriveName/lime-forensics-1.1-r17/src$ sudo insmod lime-3.2.0-59-generic.ko "path=/media/USBDriveName/myRAMDump.lime format=raw"
It is important that you put both the path parameter and the format parameter in the command, otherwise you’ll get the “-1 invalid parameters” error. The documentation also says that for Ubuntu you’ll need the quotes around the path and format parameters, while in other distributions like CentOS and RedHat you won’t need them.
NB: I compiled it directly on a USB drive and used it as is on the same USB
More about the LiME Linux Memory Extractor can be found in their documentation at the Google Code repository. There’s a PDF with the documentation that you can download (https://code.google.com/p/lime-forensics/downloads/list)