Memory dumping Android

  • I need to evaluate the security of a cryptographic library. In particular I am targeting a part of the library where I believe the private key is exposed for a limited time in the RAM. Any ideas or pointers on how to go about checking the RAM for this key. I was thinking about dumping memory after some specific user interactions. But how do I start with this, any tools recommended? I am home in the security world, I know about memory layouts, usage, countermeasures against memory attacks etc. Just not in Android.

    As for starter it is sufficient if the tools/techniques require custom kernel flashing or rooted devices. But in the end it should be applicable in real life situations where the target device is an out-of-the-box OEM device.

    Are you expecting a software-only solution (e.g. malware) or for the attacker to have physical access to the device?

    Both are within scope of my assessment. What are you thinking about?

    The simplest way would be to gain kernel or root privs and simply read it off the FS. Otherwise, gain ptrace privs and rack the process memory for e.g. "BEGIN PRIVATE KEY" (depends on the key format). Then, there was this flush+reload attack, not sure whether it is applicable -- might be. I guess that's about it from the SW perspective. Note that the key will obviously be in memory since the library has to process it somehow, and this doesn't count as an issue. The issue would be not scrubbing memory after the processing is done.

    Physical attacks would depend on whether the key was flushed from caches or not. If not, then sorry. If yes, then you could e.g. tap the traces and record the traffic, looking for access patterns specific to what the library does. Note this may be a bit convoluted due to caching and multitasking. Or, you could try halting the system and dumping the whole RAM chip. Both don't look very realistic to me, though, much easier to get the flash chip out and dump it, reading data from FS.

    Since this looks like you first post, the very nature of this question make me wonder what you are really looking for...

    How do you mean @KristoferA what are you insinuating? :-) Just healthy interest and interning as a security engineer :-) I have to start somewhere with my first post :-)

    @4oxer just a hunch... your question is very targeted. Not trying to do anything illegal, right?

    Interning as a security engineer :-) no worries. Checkout my profile, I am very transparent. Although I could have forged that too ;-) anyhow thanks for your concern, but no it is fully legal.

  • I had the same need and after looking around I ended up writing my own program.

    Usage:

    memdump <pid>
    memdump <pid> <ip-address> <port>
    

    The former will output the entire process memory to stdout, and the latter to the TCP port of your choice (you'll likely use netcat on the other end).

    #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);
        }
    }
    

    To cross-compile it for Android your Android.mk should look like this:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := memdump
    LOCAL_SRC_FILES := memdump.c
    include $(BUILD_EXECUTABLE)
    

    What a great response! To build this you need the android NDK. Make a subfolder called 'jni', and in it place the first block in a file named 'memdump.c' and the second block in a file named 'Android.mk', then run ndk-build from the NDK

    See also LiME which allows memory dump of the entire device, rather than a specific process: https://github.com/504ensicsLabs/LiME

    I had to change the `int main` to `void main` to make it work because for some reason my compiler was complaining that the `main` function was not returning anything. Without this small change, I was getting a couple of errors because of the many `return` statements without return variables.

  • You can dump the memory info using the Android Debug Bridge (ADB) by using the following command:

    adb shell dumpsys meminfo > mem.txt
    

    To get info for a particular app, use this:

    adb shell dumpsys meminfo 'your apps package name'
    

    This answer gives a detailed overview of the dumpsys tool. Do take a look. Also, this blog post explains another method to dump the memory of a particular running process (just found it in my Google search result).

    that only dumps the amount of memory an app uses?

    Updated my answer. Take a look.

    This works if the device is not rooted?

    This doesn't actually dump memory, only prints some general statistics on memory usage.

  • You can use GameGuardian for this. Need root.

    Memory editor tab - menu - memory dump - select range and folder - press ok - wait for toast "Dump end".

    Here some video examples how to do this:

  • You also have a built-in tool in Android-Studio for that, which is called 'Profiler'.

    You can profile from:

    1. Attach the Profiler to the device (further explanation here)
    2. hprof file (can be generated by the 'heapdump' command in the device shell)

    Example of using the Profiler:

    Profiler Example

    The picture you posted is too small to be useful. Did you accidentally post a thumbnail?

    Thank you for the comment, I will fix it

  • There are techniques to capture the Android RAM into a memory file or dump much like you could with any desktop OS and analyze the mem dump using a framework like volatility.For Android it is more than likely that you have to root the device. If you have the time this is a great 2 part guide on extracting Android memory that starts here https://www.youtube.com/watch?v=KN9kxn6htMU

    Using volatility you could extract strings, see running process etc... The volatility foundation has a great blog post here on identifying AES encryption keys for true crypt in a memory dump. http://volatility-labs.blogspot.com/2014/01/truecrypt-master-key-extraction-and.html

    It sounds like you could use a very similar methodology in your use case. I hope this can be of some assistance.

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM

Tags used