Hacking Shared Preferences on non-rooted Android devices
While attempting to analyze applications, I often face the problem that they only allow
ARM devices to launch them. You can simply check that by looking at the folder lib
when after unzipping an APK.
Then you need a rooted device if you want to checkdynamic data about the application.
The goal of this article is to show you how you can easily modify an application to analyse the internal files created.
Looking at internal files
When you install an application, its internal folder is located on an Android device in : data/data/<package_name>/
and can contain assets, libs, databases, shared preferences, etc.
herolte:/data/data/com.example.application $ ls
app_.gpg.classloader app_webview code_cache files shared_prefs
app_textures cache databases lib
But if you try to list its files without rooting your phone, you will quickly face a wall, you don’t have the permissions to read the content.
herolte:/ $ ls /data/data/com.example.application
ls: /data/data/com.example.application: Permission denied
1|herolte:/ $ id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid) context=u:r:shell:s0
Making possible to look at it without root
For a developper, it’s important for debugging purpose to make the files used available, so you can flag an android application as debuggable to be able to access the filesystem.
In the Manifest.xml
:
<manifest ...>
...
<application ... android:debuggable="true">
...
</application>
</manifest>
So here is the trick, we can recompile an application to make it debuggable simply with apktool && sign.jar
$ apktool d test_app.apk
$ # Then you add the debuggable flag to the Manifest.xml
$ apktool b test_app/ -o test_app.modified.apk
$ java -jar sign.jar test_app.modified.apk
$ adb install test_app.modified.s.apk
Here we are, you are now able to launch a shell with the rights to access the application internal’s :
$ adb run-as com.example.application
> ls
cache
code_cache
lib
shared_prefs
> id
id=10170(u0_a170) gid=10170(u0_a170) groups=10170(u0_a170),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid) context=u:r:untrusted_app:s0:c170,c256,c512,c768
Playing with shared preferences
Shared preferences are often used as save file for internal configurations of an application. Vulnerability related to their access exist and can be very dangerous (MODE_WORLD_WRITEABLE
, MODE_WORLD_READABLE
, etc.) but here my goal will be to use them to demonstrate of a game cheat can work.
However I do not encourage you to cheat in games.
Let’s take an example game named EasySharedGame
, after playing few hours, you are frustrated an want to unlock the God Staff of mothafucka destructor
but it cost a lot of money and you don’t have such time because you’re a busy person.
After playing for a while you’ve got 9547
pounds.
First step is to close the the game and see if such value exists in the shared preferences.
So we will grep like a forensic ctf player
and here , magic there is a file match:
$ grep -lre 9547 .
./shared_prefs/playerprefs.xml
$ grep 9547 ./shared_prefs/playerprefs.xml
<int name="money_count" value="9547" />
You can change this value to 99999999
and become the hero you always wanted to be.
Now imagine you want your bestfriend to be able to have that much money but he know nothing about Android stuff.
I’ll show you how to make it permanent so you’ll be the hero of you’re friend too.
First keep the apktool
decompilation output.
Then in the Manifest.xml
you will look for the first activity launched.
Here we will take UnityPlayerActivity
:
<activity android:label="@string/app_name" android:maxAspectRatio="1.86" android:name="com.unity3d.player.UnityPlayerActivity" android:resizeableActivity="false" android:screenOrientation="sensorLandscape">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
</activity>
In the smali
folder search for the associated package com/unity3d/player
and add the file CheatClass.smali
containing the following code ( I simply generated this Samli by compiling a test application and extracted it with apktool) :
.class public Lcom/unity3d/player/CheatClass; # Here change your package name
.super Ljava/lang/Object;
.source "CheatClass.java"
.method public constructor <init>()V
.locals 0
.line 6
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public static moreCoinsPlz(Landroid/app/Activity;)V
.locals 4
.param p0, "context"
.line 9
const-string v0, "player_prefs" # Here change the preference file name
const/4 v1, 0x0
invoke-virtual {p0, v0, v1}, Landroid/app/Activity;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
move-result-object v0
.line 10
.local v0, "sp":Landroid/content/SharedPreferences;
invoke-interface {v0}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;
move-result-object v1
.line 11
.local v1, "editor":Landroid/content/SharedPreferences$Editor;
const-string v2, "money_count" # Here the key name
const v3, 0x5f5e0ff # And here the value to change
invoke-interface {v1, v2, v3}, Landroid/content/SharedPreferences$Editor;->putInt(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor;
.line 12
invoke-interface {v1}, Landroid/content/SharedPreferences$Editor;->apply()V
.line 13
return-void
.end method
And in UnityPlayerActivity
search the function onCreate
and add this to the smali
code :
.method protected onCreate(Landroid/os/Bundle;)V
...
move-object v0, p0
check-cast v0, Landroid/app/Activity;
invoke-static {v0}, Lcom/unity3d/player/CheatClass;->moreCoinsPlz(Landroid/app/Activity;)V # change the package name of CheatClass
...
.end method
Recompile and sign it. Tadam your friends have a cheated version too.
(if you forgot : apktool b base/ -o cheat.apk && java -jar sign.jar cheat.apk
)
After the first launch the shared_pref will contain the modified value :
herolte: $ cat player_prefs.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<int name="money_count" value="99999999" />
</map>