Reverse Engineering and Modifying an Android Game

· 818 words · 4 minute read

Intro 🔗

Welcome! In this post, I’ll be talking about how to reverse engineer an Android game, modify it according to our preferences, and recompile it into an APK.

My game of choice is the very fun “Dr. Driving.” Why? Because it’s a fun game to play, and there is something I think I can improve in it.

My goal is to make the Highway mission infinite so the game doesn’t end after any checkpoint and I can keep playing it.

Decompiling the APK/Game 🔗

We are going to use a very popular tool called apktool. Download the JAR file and save it somewhere like C:\apktool (Linux and macOS users can figure this out on their own). Don’t forget to add this to your PATH.

I have downloaded a modded APK of the app from the internet. Let’s decompile the APK using apktool: apktool d your_apk.apk.

dr_driving_apktool_terminal

This will create a folder with the same name, which will include the codebase. Don’t get too excited; it’s not the native Java or Kotlin code that you can edit and recompile back into the APK. Most of it is in Smali code. Smali is an intermediate language between the DEX (Dalvik Executable) format and Java. DEX is the bytecode of the Dalvik Virtual Machine (DVM) that powers Android.

You might want to take some time to familiarize yourself with Smali, DEX, and DVM. These links will give you a basic understanding of DEX and Smali, but feel free to read about them in detail.

Now that you know a bit about Smali and DEX, we can start exploring the codebase. The actual code is located in drdriving/smali/com/ansangha/drdriving/. There are weird file names such as a.smali, b.smali. This is purposely done to make it harder to read and understand the codebase — a process known as code obfuscation.

Reading the Kotlin/Java Native Code? 🔗

Let’s try to read the native Java/Kotlin code using another useful tool called jadx. Open the APK file in jadx GUI.

We can start reading the Java/Kotlin code now. Click on the home button in the top bar to open the main activity/main page of the app. It’s up to us how well we read and understand the code and control flow of the program.

dr_driving_apk_jadx_gui

Since I have already read and understood the codebase a bit, here’s what I know about it: The update() method inside the ViewOnTouchListener class is responsible for updating the game loop. It has game modes associated with it:

Game Mode Action
0 Loading screen
1 Car selection menu
3 Actual game and game movement
4 Pause
5 End of the game

This is very clear from reading this Java code.

dr_driving_jadx_update_method

Exploring the codebase a bit more, we stumble upon this method that returns true or false depending on whether we have passed the checkpoint or not. I don’t have a concrete idea of how this exactly works, but it seems to return a boolean.

dr driving bpass checkpoint

Some other things are pretty noticeable, such as the mission_type. We know this is important because there are several missions, and we only want to modify the highway mission. But how do we find out which method is which? Most of the time we can find everything in the code itself.

dr driving mission highway

Now, we might think it’s easy to modify the code — maybe do something like this so whenever the mission type is 1, we never return true, resulting in an infinite loop:

if (this.g_iMissionType == 1) {
  return false;
}

This approach is correct; however, I am not sure if there is a way to write native Java code and compile it back to Smali and DEX. Instead, we are going to edit the Smali code by hand and then use apktool to build the APK. Let’s find the Smali file; we can use editor magic to look for the method named bPassCheckPoint

dr driving bpasscheckpoint

Understand a bit of what is happening in this code: the v0 is the register being loaded with the value of g_iMissionType, and then v1 and v2 are loaded with 0x4 and 0x5 for comparison with the v0 register. Let’s edit this code and add our condition.

const/4 v1, 0x1 # Load v1 with 0x1
if-eq v0, v1, :return_false # If v0 equals v1, go to label return_false
... other code here ..... 
:return_false:
const/4 v1, 0x0 # Load v1 with 0x0 (false; 0 = false, 1 = true)
return v1

We have now successfully modified the code to always return false whenever the mission is Highway. Building this APK is very simple; we use apktool and provide it with the directory where all the decompiled code is apktool b .

Also, note that we will have to sign the APK in order to install it on any Android device.

This was a very simple modification, but it helped me and hopefully you too , to get a basic understanding of reverse engineering Android apps and modifying them.