Archive

Posts Tagged ‘NDK’

Android Process Memory Dumps with Memdump – Android 4.4+ (on Ubuntu 16.04)

December 27, 2016 2 comments

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.mkfile, 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