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
.
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.
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.
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.
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.
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
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.