Introduction

Long back I had written about how we can reverse engineer an Android App and learn its code here. But for the longest time, I wanted to try and re-assemble the reverse-engineered APK (obviously for education purposes!) but I never tried or understood it. Finally, one night I sat with a stomach ache trying to reassemble a reverse-engineered APK of a dummy app I wrote, and TLDR; I vomited right after I was able to run the modified APK! :p

To understand if the disassembled app worked with the modified code, I wrote a simple application where a SharedPreference value was responsible for a toast message –

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

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

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val setValue = false

        val sharedPreferences: SharedPreferences = applicationContext.getSharedPreferences(
            "SharedPref", MODE_PRIVATE)
        sharedPreferences.edit().putBoolean("hello", setValue).apply()
        if (sharedPreferences.getBoolean("hello", false)) {
            Toast.makeText(this, "Toast for hello", Toast.LENGTH_LONG).show()
        }
    }
}

Now that we’ve set this up and generated the APK, our de-assembling process beings.

Disassembling an APK

Disassembling is easier than you thought (if you’ve come here after reading my reverse engineering article, you would already be aware of it).

We’ll use an open-source tool apktool.
To begin with, we just need to get the latest Jar file from the News section on the page and download it.

Next, copy the Jar to a directory where you have the APK file and run the below command –
java -jar apktool.jar d -r basicapp.apk

This will give us a directory with a lot of things in it but for now, we have to look at the smali_classes directories.

Smali Files – Smali Files are basically assembly language code which the Android Dalvik Virtual Machine understands and are the executables file for them. The Java/Kotlin code is converted into .DEX file and when we decompile the .DEX file, we get the Smali Files.

There is where our decompiled code is. Now, we just have to search for the package across these directories and see where our activity/fragment/viewmodel or whichever file we are searching for is.

varun:~ varun$ cd Desktop/
varun:Desktop varun$ cd basicapp
varun:basicapp varun$ cd smali_classes3/
varun:smali_classes3 varun$ cd com/example/demoapp/
varun:demoapp varun$ ls
BuildConfig.smali
FirstFragment$$ExternalSyntheticLambda0.smali
FirstFragment.smali
MainActivity.smali
SecondFragment$$ExternalSyntheticLambda0.smali
SecondFragment.smali
varun:demoapp varun$ vim MainActivity.smali

You can open the file in any notepad editor and the above code will look something like this –

    invoke-virtual {v0}, Lcom/example/demoapp/databinding/ActivityMainBinding;->getRoot()Landroidx/coordinatorlayout/widget/CoordinatorLayout;

    move-result-object v0

    check-cast v0, Landroid/view/View;

    invoke-virtual {p0, v0}, Lcom/example/demoapp/MainActivity;->setContentView(Landroid/view/View;)V

    .line 20
    const/4 v0, 0x1

    .line 22
    .local v0, "setValue":Z
    invoke-virtual {p0}, Lcom/example/demoapp/MainActivity;->getApplicationContext()Landroid/content/Context;

    move-result-object v1

    .line 23
    nop

    .line 22
    const-string v2, "SharedPref"

    const/4 v3, 0x1

    invoke-virtual {v1, v2, v3}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;

    move-result-object v1

    const-string v2, "applicationContext.getSh\u2026haredPref\", MODE_PRIVATE)"

    invoke-static {v1, v2}, Lkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V

    .line 24
    .local v1, "sharedPreferences":Landroid/content/SharedPreferences;
    invoke-interface {v1}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;

    move-result-object v2

    const-string v4, "hello"

    invoke-interface {v2, v4, v0}, Landroid/content/SharedPreferences$Editor;->putBoolean(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor;

    move-result-object v2

    invoke-interface {v2}, Landroid/content/SharedPreferences$Editor;->apply()V

    .line 25
    invoke-interface {v1, v4, v3}, Landroid/content/SharedPreferences;->getBoolean(Ljava/lang/String;Z)Z

    move-result v2

    if-eqz v2, :cond_1

    .line 26
    move-object v2, p0

    check-cast v2, Landroid/content/Context;

    const-string v3, "Toast for hello"

    check-cast v3, Ljava/lang/CharSequence;

    const/4 v4, 0x1

    invoke-static {v2, v3, v4}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

    move-result-object v2

    invoke-virtual {v2}, Landroid/widget/Toast;->show()V

    .line 28
    :cond_1
    return-void
.end method

Here, we have to look at –
const/4 v3, 0x0

This is basically our ‘val setValue = false

In smali code, false is 0x0, and true is 0x1.
As you would’ve guessed, we have to change this line from 0x0 to 0x1. Which will eventually make setValue true.

After doing that, save the file. That’s it, we’ve modified the code. Now we have to re-assemble the APK.

Reassembling an APK

Now to re-assemble the APK, we will use the same apktool.

Running the following command gives us an APK –

java -jar apktool.jar b basicapp

We’ll have to sign the APK to install it on our device. To do that, run the following commands –

keytool -genkey -v -keystore my-keystore.keystore -alias name_alias -keyalg RSA -validity 10000
jarsigner -verbose -keystore varun.keystore basicappmodified.apk varun

If you run into the following error –

Failure [-124: Failed parse during installPackageLI: Targeting R+ (version 30 and above) requires the resources.arsc of installed APKs to be stored uncompressed and aligned on a 4-byte boundary]

You’ll have to follow some extra steps and the Convert APK GitHub repository here has a very quick way to fix it. Run their script on your signed APK and it fixes the above warning for you.

Install the APK and see the toast showing up!

References

  1. https://proandroiddev.com/how-i-hacked-an-android-app-for-a-premium-feature-d9ca74e797ad
  2. https://www.syssec-project.eu/m/page-media/158/syssec-summer-school-Android-Code-Injection.pdf

The End

And that’s how we can disassemble, read through the code, modify it, and reassemble it! This is just for educational purposes and I am sure none of you would want to use this for any piracy or any such thing.

My next article would be a detailed explanation on different type of security measures we can adopt (and how it can be wore down by a third person).

If you like the article, might as well give it a like below? 😀

Leave a Reply

Your email address will not be published. Required fields are marked *