How can one pull the (private) data of one's own Android app?

前端 未结 14 1731
长发绾君心
长发绾君心 2020-11-30 16:44

Attempting to pull a single file using

adb pull /data/data/com.corp.appName/files/myFile.txt myFile.txt

fails with

failed          


        
相关标签:
14条回答
  • 2020-11-30 17:07

    adb backup will write an Android-specific archive:

    adb backup  -f myAndroidBackup.ab  com.corp.appName
    

    This archive can be converted to tar format using:

    dd if=myAndroidBackup.ab bs=4K iflag=skip_bytes skip=24 | openssl zlib -d > myAndroidBackup.tar
    

    Reference:

    http://nelenkov.blogspot.ca/2012/06/unpacking-android-backups.html

    Search for "Update" at that link.


    Alternatively, use Android backup extractor to extract files from the Android backup (.ab) file.

    0 讨论(0)
  • 2020-11-30 17:08

    This answer is based on my experience with other answers, and comments in the answers. My hope is I can help someone in a similar situation.

    I am doing this on OSX via terminal.

    Previously Vinicius Avellar's answer worked great for me. I was only ever most of the time needing the database from the device from a debug application.

    Today I had a use case where I needed multiple private files. I ended up with two solutions that worked good for this case.

    1. Use the accepted answer along with Someone Somewhere's OSX specific comments. Create a backup and use the 3rd party solution, sourceforge.net/projects/adbextractor/files/?source=navbar to unpack into a tar. I'll write more about my experience with this solution at the bottom of this answer. Scroll down if this is what you are looking for.

    2. A faster solution which I settled with. I created a script for pulling multiple files similar to Tamas' answer. I am able to do it this way because my app is a debug app and I have access to run-as on my device. If you don't have access to run-as this method won't work for you on OSX.

    Here is my script for pulling multiple private files that I'll share with you, the reader, who is also investigating this awesome question ;) :

    #!/bin/bash
    #
    # Strict mode: http://redsymbol.net/articles/unofficial-bash-strict-mode/
    set -euo pipefail
    IFS=$'\n\t'
    
    # 
    # Usage: script -f fileToPull -p packageName
    # 
    
    # This script is for pulling private files from an Android device
    # using run-as. Note: not all devices have run-as access, and
    # application must be a debug version for run-as to work.
    # 
    # If run-as is deactivated on your device use one of the
    # alternative methods here:
    # http://stackoverflow.com/questions/15558353/how-can-one-pull-the-private-data-of-ones-own-android-app
    # 
    # If you have encrypted backup files use:
    # sourceforge.net/projects/adbextractor/files/?source=navbar 
    # From comments in the accepted answer in the above SO question
    # 
    # If your files aren't encrypted use the accepted answer 
    # ( see comments and other answers for OSX compatibility )
    # 
    # This script is open to expansions to allow selecting 
    # device used. Currently first selected device from
    # adb shell will be used.
    
    #Check we have one connected device
    adb devices -l | grep -e 'device\b' > /dev/null
    
    if [ $? -gt 0 ]; then
        echo "No device connected to adb."
        exit 1
    fi
    
    # Set filename or directory to pull from device
    # Set package name we will run as
    while getopts f:p: opt; do
        case $opt in
            f)
                fileToPull=$OPTARG
                ;;
            p)
                packageName=$OPTARG
                ;;
        esac
    done;
    
    # Block file arg from being blank
    if [ -z "$fileToPull" ]; then
        echo "Please specify file or folder to pull with -f argument"
        exit 1
    fi
    
    # Block package name arg from being blank
    if [ -z "$packageName" ]; then
        echo "Please specify package name to run as when pulling file"
        exit 1
    fi
    
    # Check package exists
    adb shell pm list packages | grep "$packageName" > /dev/null
    if [ $? -gt 0 ]; then
        echo "Package name $packageName does not exist on device"
        exit 1
    fi
    
    # Check file exists and has permission with run-as
    fileCheck=`adb shell "run-as $packageName ls $fileToPull"`
    if [[ $fileCheck =~ "Permission denied" ]] || [[ $fileCheck =~ "No such file or directory" ]]; then
        echo "Error: $fileCheck"
        echo "With file -> $fileToPull"
        exit 1
    fi
    
    # Function to pull private file
    #
    # param 1 = package name
    # param 2 = file to pull
    # param 3 = output file
    function pull_private_file () {
    
        mkdir -p `dirname $3`
    
        echo -e "\033[0;35m***" >&2
        echo -e "\033[0;36m Coping file $2 -> $3" >&2
        echo -e "\033[0;35m***\033[0m" >&2
    
        adb shell "run-as $1 cat $2" > $3
    }
    
    # Check if a file is a directory
    # 
    # param 1 = directory to check
    function is_file_dir() {
    
        adb shell "if [ -d \"$1\" ]; then echo TRUE; fi"
    }
    
    # Check if a file is a symbolic link
    # 
    # param 1 = directory to check
    function is_file_symlink() {
    
        adb shell "if [ -L \"$1\" ]; then echo TRUE; fi"
    }
    
    # recursively pull files from device connected to adb
    # 
    # param 1 = package name
    # param 2 = file to pull
    # param 3 = output file
    function recurse_pull_private_files() {
    
        is_dir=`is_file_dir "$2"`
        is_symlink=`is_file_symlink "$2"`
    
        if [ -n "$is_dir" ]; then
    
            files=`adb shell "run-as $1 ls \"$2\""`
    
            # Handle the case where directory is a symbolic link
            if [ -n "$is_symlink" ]; then
                correctPath=`adb shell "run-as $1 ls -l \"$2\"" | sed 's/.*-> //' | tr -d '\r'`
                files=`adb shell "run-as $1 ls \"$correctPath\""`
            fi
    
            for i in $files; do
    
                # Android adds nasty carriage return that screws with bash vars
                # This removes it. Otherwise weird behavior happens
                fileName=`echo "$i" | tr -d '\r'` 
    
                nextFile="$2/$fileName"
                nextOutput="$3/$fileName"
                recurse_pull_private_files "$1" "$nextFile" "$nextOutput"
            done
        else
    
            pull_private_file "$1" "$2" "$3"
        fi
    }
    
    recurse_pull_private_files "$packageName" "$fileToPull" "`basename "$fileToPull"`"
    

    Gist: https://gist.github.com/davethomas11/6c88f92c6221ffe6bc26de7335107dd4


    Back to method 1, decrypting a backup using Android Backup Extractor

    Here are the steps I took on my Mac, and issues I came across:

    First I queued up a backup ( and set a password to encrypt my backup, my device required it ):

    adb backup -f myAndroidBackup.ab  com.corp.appName
    

    Second I downloaded just abe.jar from here: https://sourceforge.net/projects/adbextractor/files/abe.jar/download

    Next I ran:

    java -jar ./abe.jar unpack myAndroidBackup.ab myAndroidBackup.tar
    

    At this point I got an error message. Because my archive is encrypted, java gave me an error that I needed to install some security policy libraries.

    • So I went to http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html and downloaded the security policy jars I needed. Now in my case the install instructions told me the wrong location to put the jar files. It says that the proper location is <java-home>/lib/security. I put them there first and still got the error message. So I investigated and on my Mac with Java 1.8 the correct place to put them was: <java-home>/jre/lib/security. I made sure to backup the original policy jars, and put them there. Vola I was able to enter a password with abe.jar and decrypt to a tar file.

    Lastly I just ran ( after running previous command again )

    tar xvf myAndroidBackup.tar
    

    Now it is important to note that if you can just run-as and cat, it is much much faster. One, you only get the files you want and not the entire application. Two, the more files ( + encryption for me ) makes it slower to transfer. So knowing to do this way is important if you don't have run-as on OSX, but the script should be first goto for a debug application.

    Mind you I just wrote it today and tested it a few times, so please notify me of any bugs!

    0 讨论(0)
  • 2020-11-30 17:09

    I had the same problem but solved it running following:

    $ adb shell
    $ run-as {app-package-name}
    $ cd /data/data/{app-package-name}
    $ chmod 777 {file}
    $ cp {file} /mnt/sdcard/
    

    After this you can run

    $ adb pull /mnt/sdcard/{file}
    
    0 讨论(0)
  • 2020-11-30 17:13

    Here is what worked for me:

    adb -d shell "run-as com.example.test cat /data/data/com.example.test/databases/data.db" > data.db
    

    I'm printing the database directly into local file.

    0 讨论(0)
  • 2020-11-30 17:14

    If you are using a Mac machine and a Samsung phone, this is what you have to do (since run-as doesn't work on Samsung and zlib doesn't work on Mac)

    1. Take a backup of your app's data directory adb backup -f /Users/username/Desktop/data.ab com.example

    2. You will be asked for a password to encrypt in your Phone, don't enter any. Just tap on "Back up my data". See How to take BackUp?

    3. Once successfully backed up, you will see data.ab file in your Desktop. Now we need to convert this to tar format.

    4. Use Android Backup Extractor for this. Download | SourceCode

    5. Download it and you will see abe.jar file. Add this to your PATH variable.

    6. Execute this to generate the tar file: java -jar abe.jar unpack /Users/username/Desktop/data.ab /Users/username/Desktop/data.tar

    7. Extract the data.tar file to access all the files

    0 讨论(0)
  • 2020-11-30 17:15

    Starting form Dave Thomas script I've been able to write my own solution to overcome 2 problems:

    1. my backup was containing only the manifest file
    2. binary files got with Dave Thomas where unreadable

    This is my script, that copies app data to sdcard and then pull it

    #Check we have one connected device
    adb devices -l | grep -e 'device\b' > /dev/null
    
    if [ $? -gt 0 ]; then
        echo "No device connected to adb."
        exit 1
    fi
    
    # Set filename or directory to pull from device
    # Set package name we will run as
    while getopts f:p: opt; do
        case $opt in
            f)
                fileToPull=$OPTARG
                ;;
            p)
                packageName=$OPTARG
                ;;
        esac
    done;
    
    # Block package name arg from being blank
    if [ -z "$packageName" ]; then
        echo "Please specify package name to run as when pulling file"
        exit 1
    fi
    
    # Check package exists
    adb shell pm list packages | grep "$packageName" > /dev/null
    if [ $? -gt 0 ]; then
        echo "Package name $packageName does not exist on device"
        exit 1
    fi
    
        adb shell "run-as $packageName cp -r /data/data/$packageName/ /sdcard/$packageName"
        adb pull /sdcard/$packageName
        adb shell rm -rf /sdcard/$packageName
    
    0 讨论(0)
提交回复
热议问题