Skip to content

Instantly share code, notes, and snippets.

@michpohl
Last active January 25, 2021 15:20
Show Gist options
  • Save michpohl/2541486cc7c0aa9a4437a71114cd3410 to your computer and use it in GitHub Desktop.
Save michpohl/2541486cc7c0aa9a4437a71114cd3410 to your computer and use it in GitHub Desktop.
How to find information from an installed Android app's SharedPreferences (if you have access to the keystore)

How to find information from an installed Android app's SharedPreferences (if you have access to the keystore)

Prerequisite: Yes, you can gain some nice insights following this How-To, but you can only get to the end of it if you're legitimized to do so (you need to have the app's keyStore and the passwords to it!)

You should also have the Android Debug Bridge (adb) installed as well as Android Studio.

1. Install the app on your phone

You might want to use it a bit and play around with it so all the data you might be looking for in sharedPreferences gets generated.

2. Find the app's package name

Go to the Play Store website, search for your app, and open the app's page. Now you can just copy the package name from the address bar If you're offline you can also use your terminal and adb to see if there's a package that might be fitting (Your phone needs to be connected via USB and Developer options & USB debugging need to be activated):

$ adb shell pm list packages | grep [part of assumed package name]

The terminal will output any package name on the phone containing your entered string.

3. Find the path to the actual apk on the phone using this command:

$ adb shell pm path [my package name]

This will return the apk file's location, something like this:

package:/data/app/[my package name]-y014EExkOnBv6hdiH4tkwA==/base.apk

As you can see, the actual file's name has a randomized part and is usual renamed to ...base.apk.

4. Download the file from the phone

Again, you will need adb to do this.

adb pull ./data/app/[my package name]-y014EExkOnBv6hdiH4tkwA==/base.apk

This pulls the file into your current folder. adb lets you specify a destination folder too, just add at as the last argument.

5. Analyze the apk file

In Android Studio, go to Build -> Analyze APK...

analyze

This will open a dialog where you have a lot of options. For now, you want to take a look at AndroidManifest.xml. In this file you find the versionCode and versionName. To be able to "update" our app you want to sideload later you have to make sure that it's a higher version than the installed one. For this it is very helpful to know the values as they can be hard to guess.

manifest

6. Change your app's application Id to the found package name

Open you app's build.gradlefile and change the applicationId to the package name you retrieved earlier.

app_id

Now you need to also change versionCode and versionName to something that is higher than the values you found out earlier. Probably versioncode is all you need, but for good measure, I do both just in case.

7. Add code to read and log SharedPreferences

Your app needs to be able to log out the saved entries. This is actually surprisingly easy, if you have the name the app stores the preferences under(You should obtain it from whoever gave you the keyStore, if you are legitimately doing all this) For example, use something like this to read out and log all content of the files right when your app's acrtivity starts:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        logSharedPreferencesContent()
    }

    fun logSharedPreferencesContent() {
        val prefs = getSharedPreferences("your key", Context.MODE_PRIVATE)
        Log.i("prefs", "Information stored in SharedPreferences:")
        prefs.all.forEach {
            Log.i("prefs", "key: ${it.key}, value: ${it.value}")
        }
    }

That's all you need.

Now, if you don't have that, you can still check what the app is storing. This slightly changed example prints the contents of all preferences files into your logs:

    fun testSharedPrefs() {
        val prefsdir = File(applicationInfo.dataDir, "shared_prefs")
        val path = prefsdir.path
        if (prefsdir.exists() && prefsdir.isDirectory) {
            val list = prefsdir.list();
            list.forEach {
                val file = File("$prefsdir.path/$it")
                Log.i("prefs", "\n${file.readText()}\n")
            }
        }
    }

Of course, you could also do something else depending on your use case, like store the files somewhere or whatever your need is here. But how do you actually get this code to work?

8. Generate a signed apk

As stated before you need access to the original keystore and its passwords (This also means: If you choose to use a keystore managed by Google, you're out of luck. Even as the legitimate app's owner you won't have access to it). This is why: You have to create a properly signed apk file and sideload it onto your device. So, generate your apk by clicking on Generate Signed Bundle/APK from the Build menu in Android Studio (or however else you generate your signed builds).

9. Sideload apk

To get the app onto the phone, it's easiest to use adb again: On most Android devices, one of these commands

// variant 1
$ adb push [path/to/myApp.apk] ./sdcard

// variant 2
$ adb push [path/to/myApp.apk] ./storage/emulated/0

will place the apk file in your phone's public root directory, where you can find it with any file browser you might have installed. Get one if you don't have one. Find the file on the phone, click to open it and install your apk as an update to the app you're targeting.

Screenshot 2020-11-27 at 13 30 38

Your existing data will not be lost. This is why we're doing all this.

10. Read your logs.

Open your app and check your logs (or wherever else you redirect the data to) to find the information you need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment